Architecture
Central platform
The central platform is a set of Docker Compose services:
- Backend (Go). The API server (chi router, pgx for PostgreSQL). Owns authentication (JWT), the host/service/hostgroup/dashboard/discovery/ dependency/cloud/notification REST API, the AI prompt endpoint (direct HTTP calls to the Anthropic Messages API — no SDK), and ingestion endpoints for the Agent, Probe, and Perimeter Probe. Reads Zeek’s rotated logs directly off a shared volume and writes bootstrap/migration state to PostgreSQL on startup.
- Frontend (React + TypeScript + Vite). The web UI: dashboard builder,
host/service views, discovery inbox, dependency topology map, AI chat
panel, and admin screens. Served by the Vite dev server behind Caddy in
development; a static production build (
npm run build) served by theservestatic file server behind Caddy in production. Talks to the backend over/api. - Icinga 2. The active-check monitoring engine (hosts, services, notifications). The backend drives it entirely through its REST API and config sync — Eon Aethis does not modify or embed Icinga 2 code.
- PostgreSQL. The application database: users, hosts, services,
dashboards, discovery jobs, dependencies, cloud connections, audit log, and
other relational state (see the
go-backend/migrationshistory for the full schema evolution). - VictoriaMetrics. Time-series storage for Icinga performance data,
queried by the backend’s
/metricsendpoints in Prometheus format. - ClickHouse. Storage for high-volume probe telemetry —
probe_events,network_flows, and enrichment data from the Aethis Probe and Zeek. The probe entities (which probes exist, their pairing state) live in PostgreSQL; the events they produce live in ClickHouse. - Redis. Cache and job/event queue for the backend.
- Zeek. Passive network traffic analysis on a monitored interface,
running with
network_mode: hostandNET_RAW/NET_ADMINcapabilities. Writes rotated logs to a shared volume that the backend reads and a janitor process prunes on a retention/disk-size policy. - Caddy. Reverse proxy and TLS termination in front of the backend and
frontend. Routes
/api/*to the backend with the prefix stripped, and/agents/*,/probes/*,/probe/*directly to the backend without stripping (these are the Agent/Probe ingestion and pairing endpoints). Everything else falls through to the frontend.
Distributed collection components
These run outside Docker Compose, on the hosts and networks they observe, and pair with the central platform over the network:
- Aethis Agent. A Go binary installed on individual monitored hosts. Runs local system metrics collection (CPU, memory, disk, network, processes), executes Nagios/monitoring-plugins-compatible checks and submits results to the backend (replacing NSCA), and optionally parses local web server access logs for web analytics. Registers with the backend by token or by an interactive pairing flow.
- Aethis Probe. A Go binary that passively observes a network segment: it captures live packets and NetFlow/IPFIX/sFlow exports, classifies traffic and devices, watches ARP/DHCP traffic to build a picture of what’s on the segment, and buffers events locally (SQLite) before pushing them to the backend over HTTPS at a configurable interval. Used for network discovery and flow visibility without installing an agent on every host.
- Perimeter Probe. A separately hosted, multi-tenant reconnaissance service. It performs external scans against a tenant’s public-facing infrastructure on request and calls back to that tenant’s Eon Aethis instance with results. Tenants and the probe operator authenticate each other with mutually-trusted certificates issued by an operator CA; the probe extracts the tenant ID from the client certificate’s CN on each incoming job request.
How they interact
flowchart TB
subgraph Central[Central platform — Docker Compose]
Caddy[Caddy reverse proxy]
FE[Frontend]
BE[Backend Go API]
Icinga[Icinga 2]
PG[(PostgreSQL)]
VM[(VictoriaMetrics)]
CH[(ClickHouse)]
Redis[(Redis)]
Zeek[Zeek]
end
Agent[Aethis Agent<br/>on monitored hosts]
Probe[Aethis Probe<br/>on a network segment]
Perimeter[Perimeter Probe<br/>external, multi-tenant]
User((Operator / browser))
User -- HTTPS --> Caddy
Caddy -- "/api/*" --> BE
Caddy -- "everything else" --> FE
Caddy -- "/agents/*, /probes/*, /probe/*" --> BE
BE -- REST API --> Icinga
BE --> PG
BE -- perf data query --> VM
BE -- probe telemetry --> CH
BE --> Redis
Zeek -- rotated logs (volume) --> BE
Icinga -- perf data writer --> VM
Agent -- "register, heartbeat,<br/>metrics, check results" --> BE
Probe -- "pair, push buffered events" --> BE
Perimeter -- "mTLS callback with scan results" --> BE
BE -- "dispatch scan job (mTLS)" --> Perimeter
A browser request goes through Caddy, which routes API calls to the backend and everything else to the frontend. The backend is the hub: it drives Icinga 2’s REST API for active checks, reads VictoriaMetrics for performance graphs, reads/writes ClickHouse for probe telemetry, and reads Zeek’s logs directly off a shared volume. The Aethis Agent and Aethis Probe are pulled in the other direction — they initiate outbound connections to the backend to register, heartbeat, and push data, so no inbound port needs to be opened on the hosts or segments they run on. The Perimeter Probe is the exception: the backend calls out to it (over mutual TLS) to start a scan, and the probe calls back with results.
AI configuration flow
The AI engine sits inside the backend and uses the Claude API’s tool-use
support to turn a prompt into a sequence of Icinga 2 API calls: it loads the
current hosts/services/hostgroups as context and asks Claude to produce the
calls needed. The backend executes every proposed action immediately, in the
same request, before the response reaches the browser — there is no dry-run,
conflict/dependency check, or operator-confirmation gate. The response
carries a requires_confirmation flag and the frontend’s chat UI renders
Confirm/Cancel buttons, but they are currently non-functional stubs: they
only relabel the chat message (“Actions confirmed and applied” /
“Actions cancelled”) and do not call the backend — by the time they’re
shown, the actions have already executed, so neither button blocks or
undoes anything.
Network discovery is different: AI-assisted discovery seeds subnets and
classifies devices, but discovered hosts and dependency proposals land in an
approval inbox (/discovery/inbox/*) that genuinely requires an operator to
approve or bulk-approve them before they take effect — unlike the AI chat
assistant above, this is a real confirmation gate.