Installation
Overview
The central platform (backend, frontend, Icinga 2, PostgreSQL, VictoriaMetrics, ClickHouse, Redis, Zeek, and Caddy) is deployed as a single Docker Compose stack. There are two compose files:
docker-compose.yml(repository root) — the development stack. Builds images from source, exposes database ports on the host for local inspection, and uses hardcoded development credentials.deploy/docker-compose.prod.yml— the production stack. Pulls pre-builteonaethis/*images, keeps internal services off the host network (only Caddy’s ports are published), and reads all credentials from.envwith no built-in defaults for secrets.
The Aethis Agent, Aethis Probe, and Perimeter Probe are installed separately on the hosts and networks they observe — see Agents & Probes.
Prerequisites
- Docker Engine with the Compose plugin (
docker compose versionworks) - A host that can reach the internet for Let’s Encrypt (production, if not using self-signed or a supplied certificate)
- Inbound access on the ports Caddy publishes (443/80 by default)
Development
From the repository root:
cp .env.example .env
# set ANTHROPIC_API_KEY if you want the AI features; everything else has a
# working development default
docker compose upThis starts nine services: caddy, backend, frontend, icinga2,
postgres, victoriametrics, redis, zeek, and clickhouse. The
development compose file publishes each service’s port on the host
(5432, 8428, 6379, 5665, 9000/8123) for local debugging, and the
backend and frontend containers bind-mount their source directories.
Reach the UI at https://localhost (self-signed certificate by default —
CADDY_TLS=internal).
ZEEK_INTERFACE defaults to eth0; set it in .env to the interface you
want Zeek to sniff. The zeek service runs with network_mode: host and
needs NET_RAW/NET_ADMIN, so it sees the host’s real interfaces rather
than a Docker bridge.
Production
Production installs ship as a package built by deploy/build-package.sh
(Docker images bundled as images.tar alongside deploy/docker-compose.prod.yml,
deploy/install.sh, deploy/upgrade.sh, and deploy/.env.example). On the
target server:
tar xzf eonaethis-<tag>.tar.gz
cd eonaethis
./install.shinstall.sh loads the bundled images, installs the shipped
docker-compose.yml (only if one doesn’t already exist — it never
overwrites an existing install), and creates .env from
deploy/.env.example if missing. It then stops and tells you to edit .env
before starting the stack; at minimum, change:
POSTGRES_PASSWORDJWT_SECRET(generate withopenssl rand -hex 32)ICINGA2_API_PASSWORDSMTP_FROMCADDY_DOMAIN
CLICKHOUSE_PASSWORD also has no default in
deploy/docker-compose.prod.yml and must be set manually — install.sh’s
own printed reminder doesn’t currently list it, but the stack won’t come up
with ClickHouse authenticated correctly until it’s set.
Alternatively, run deploy/setup.sh for an interactive wizard that prompts
for domain/TLS, email, the Anthropic API key, the network interface, and the
admin account, and writes .env for you — note that it does not currently
ask about ClickHouse at all, and the .env it writes omits
CLICKHOUSE_DB/CLICKHOUSE_USER/CLICKHOUSE_PASSWORD entirely, so add
those to the generated .env by hand before starting the stack (the
production compose file requires CLICKHOUSE_PASSWORD with no default).
Once .env is filled in:
docker compose up -dSee Configuration for the full list of environment variables, and Configuration — First-boot admin account for creating the initial admin user without calling the register endpoint by hand.
Ports
By default Caddy is the only service that binds host ports:
| Port | Service | Purpose |
|---|---|---|
| 443 | Caddy | HTTPS UI/API (override with CADDY_HTTPS_PORT) |
| 80 | Caddy | HTTP, used for ACME challenges (override with CADDY_HTTP_PORT) |
Override CADDY_HTTPS_PORT/CADDY_HTTP_PORT when another reverse proxy on
the host already owns 443/80. All other services (backend, icinga2,
postgres, victoriametrics, redis, zeek, clickhouse) are reachable
only on the Compose network, not the host, in the production compose file.
TLS
Caddy handles TLS for the platform, in one of three modes set via
CADDY_TLS:
- Self-signed (default):
CADDY_TLS=internal. - Let’s Encrypt: leave
CADDY_TLSempty and setCADDY_DOMAINto a publicly resolvable domain, with port 80 reachable for the ACME challenge. - Your own certificate:
CADDY_TLS="/etc/caddy/certs/fullchain.pem /etc/caddy/certs/privkey.pem"and pointCADDY_CERTS_DIRat the directory containing those files on the host (mounted read-only into the container at/etc/caddy/certs).
Demo traffic generator
The production compose file includes a demo-probe service behind the
demo Compose profile, disabled by default. It writes synthetic flow
events and must not be enabled on a real production install:
docker compose --profile demo up -dVerifying the install
docker compose ps
curl -k https://localhost/healthThe backend’s healthcheck hits its own /health endpoint and depends on
PostgreSQL, Icinga 2, VictoriaMetrics, and ClickHouse all reporting healthy
first, so docker compose ps showing backend as healthy implies the
whole storage/monitoring layer came up correctly.
Upgrading
tar xzf eonaethis-<newer-tag>.tar.gz
cd eonaethis # same directory as the existing install
./upgrade.shupgrade.sh loads the new images, backs up the current
docker-compose.yml and .env to a timestamped .upgrade-backup-*
directory, adds any new env vars introduced since your last install (with
defaults), shows a diff against the shipped compose file for manual merging
if your live file has diverged, then runs docker compose up -d. Postgres
migrations and the ClickHouse schema bootstrap are applied automatically by
the backend on startup, and the script waits for /health to go green
before finishing.
For upgrades that also change infrastructure (not just the backend image),
use deploy/major-upgrade.sh instead — check its output for what it does in
your specific package version before running it, since it goes further than
the routine upgrade.sh flow.