Skip to main content
For the complete documentation index, see llms.txt. Markdown versions are available by appending .md to page URLs.
Lookout is local-first. Treat its data directory, master key, API credentials, collector private keys, and backups as security-sensitive. The service should run as an unprivileged account on a dedicated host or VM, behind an authenticated TLS reverse proxy when it is reachable beyond loopback.

Automated installation

The supported installation path on x86-64 or ARM64 Linux with systemd is:
It is unattended and idempotent. Fleet mode discovers assets, uses only identity-pinned pre-authorized administrative transports, selects one central Linux host deterministically, creates a private TLS channel, enrolls a unique signed collector on each reachable supported Linux endpoint, and verifies a delivered heartbeat. Unsupported assets are recorded as coverage gaps. A failed upgrade restores the previous application release, and existing secrets and local tuning are preserved. Access probing, collector staging, installation, and heartbeat validation use bounded parallelism (eight nodes by default). Set LOOKOUT_FLEET_CONCURRENCY to an integer from 1 through 16 to tune the limit for the available network and central-host capacity. The installer streams discovery, central-service, per-node collector, survey, validation, and bootstrap-key cleanup progress to stderr while reserving stdout for its final machine-readable result. Defaults are intentionally fixed so uninstall can use an exact allowlist. Fleet central traffic uses pinned private TLS; host-local mode remains loopback-only. The generated administrator token is not printed or placed in process arguments; it is stored at /etc/lookout/admin-token with mode 0600. To remove executable code and services while preserving everything needed for recovery or reinstall:
To remove configuration, secrets, collector identity, and event data across the fleet as well, use ./uninstall.sh --purge. Purge removes only the installer’s fixed paths and deletes service users only when a protected installer manifest proves that Lookout created them. On an individual host, sudo lookout-uninstall and its explicit --purge --yes form remain available for recovery operations.

Host layout

  • Application: /opt/lookout, root-owned and not writable by either service account.
  • Server state: /var/lib/lookout, owned by lookout, mode 0700.
  • Server configuration: /etc/lookout, files owned by lookout, mode 0600.
  • Collector state: /var/lib/lookout-collector, owned by lookout-collector, mode 0700.
  • Collector identity: /etc/lookout-collector/identity, owned by lookout-collector, directory mode 0700, private files mode 0600.
The automated installer creates the accounts, configuration, and credentials. Never paste a plaintext token or master key into JSON, a unit file, an image, or source control. For a manual deployment, install the two unit files in /etc/systemd/system, inspect them with systemd-analyze security, and then enable the server and continuous collector:
The collector streams high-signal journald and Linux audit records when readable, durably queues normalized events, and normally submits a signed batch within two seconds. Inventory and health observations use the same monotonic signed stream every 60 seconds. Failed submissions retain their exact signed envelope and retry with bounded backoff. The unit receives journald access through SupplementaryGroups=systemd-journal only when that group exists; it does not run as root or modify audit policy. Missing audit visibility is reported as degraded capability rather than silently treated as coverage. Do not run multiple collector instances against the same state directory. When collectors.tailscale.enabled is true, the same collector polls bounded network-flow and configuration-audit windows, persists per-log cursor boundaries, and deduplicates inclusive API boundaries. Use a read-only credential with logs:network:read and/or logs:configuration:read, supplied only through an allowlisted environment or owner-only secret file.

Network boundary

Keep the server on 127.0.0.1 when a reverse proxy runs on the same machine. For direct Tailscale binding, require API credentials, storage encryption, Tailscale ACL restrictions, and HTTPS at the application boundary or a sidecar proxy. Do not expose Lookout directly to a LAN or the public Internet over plaintext HTTP. Firewall egress to only explicitly configured survey APIs and cloud export endpoints. The health endpoint does not contain events or graph data and is deliberately unauthenticated for local supervision. All /api/v1 routes require an authenticated principal when configured for production.

Doctor and upgrade preflight

The doctor is read-only and returns nonzero when it finds a blocking issue:
It checks Node compatibility, storage/key posture, state-file permissions, snapshot integrity and schema compatibility, event/audit journal chains, free-space headroom, and abandoned temporary files. Run it before and after every deployment. When cloud export is enabled, inspect /health for a growing pending count, retry state, or a blocked permanent failure. Correct the endpoint or credentials, then run node bin/lookout.js export-resume. Cloud state corruption is reported but does not prevent local ingestion and detection from starting. Alert webhook health is reported separately. After correcting a permanent webhook endpoint or credential failure, run node bin/lookout.js webhook-resume to unblock its durable queue. The legacy alert-webhook-resume command remains available for installations still using the deprecated alertWebhook configuration block. Upgrade one node at a time. First run preflight, create and verify an encrypted backup, stop Lookout, install the immutable application tree, run preflight again against the same data, and start the service. Never allow two versions to write the same directory. A future schema-changing release must ship an explicit, tested migration before its supported schema version is incremented. Rollback application code only when the preflight confirms the stored schema is supported by the older release. Otherwise restore a verified pre-upgrade backup into a new empty directory; restoration intentionally refuses to overwrite an existing directory.

Container deployment

The Dockerfile runs as numeric user 10001 with no bundled secrets. Mount a validated config read-only, mount master/auth/collector credential files read-only, and mount /var/lib/lookout on a volume owned by UID/GID 10001. Use a read-only root filesystem, drop all Linux capabilities, set no-new-privileges, and provide a writable tmpfs only if the runtime requires it. Terminate TLS outside the container and restrict published ports to the reverse proxy or private overlay. Pin the base image by digest in a production build pipeline and rebuild regularly. Do not copy a .env, credentials, state, or backups into the image build context.

Backup and recovery

Backups are authenticated and encrypted, but the backup and master key must still be stored separately. Periodically perform a restore drill to a new directory, run the doctor against it, and start an isolated Lookout instance to verify API reads. Alert on failed backup jobs, low disk space, repeated service restarts, collector submission gaps, and doctor failures. Retention compaction and backup must not run concurrently with another process writing the same data directory. Stop the service for a fully consistent offline backup until coordinated online snapshots are implemented.