How it works
One server binary. One node binary. A single mTLS stream. That's the whole topology.
┌─────────────────────────────────────────────┐
│ Central server (Go) │
│ gRPC + grpc-gateway (REST) · React UI │
│ ring buffer → flush → time-series store │
│ control-plane stream registry + scheduler │
│ alert engine · correlator · metrics taps │
└──────────────────▲──────────────────────────┘
│ one outbound mTLS gRPC stream each
┌────────────────────┼────────────────────┐
│ │ │
┌───┴────┐ ┌───┴────┐ ┌───┴────┐
│ node │ │ node │ │ node │
│ PoP-A │ │ branch │ │ cloud │
└────────┘ └────────┘ └────────┘
in-process scheduler behind NAT outbound-only The data path
- 1. Connect. Each probe node opens one bidirectional mTLS gRPC stream to the server and stays connected.
- 2. Assign. The server pushes test assignments down the stream; nodes resync on reconnect.
- 3. Probe. Nodes execute scheduled tests through a closed executor registry and stream results up.
- 4. Ingest. Results land in a ring buffer, flush in batches to the time-series store, and fan out to taps.
- 5. Act. The alert engine, correlator, live SSE stream, Prometheus, and OTel taps each consume the same flush.
One source of truth
Every wire shape — the node protocol, the REST API, the TypeScript client, and the OpenAPI document — is generated from a single set of protobuf definitions. There is no hand-maintained parallel schema to drift.
The default build is pure Go and CGO-free, so the server and node are single, statically-linked binaries that run anywhere — including a Raspberry Pi. SQLite is the default time-series backend, with no external database or container required.
Non-negotiables
Four design invariants shape every decision in FourEyes. They're why the architecture looks the way it does.
Outbound-only nodes
Probes never open an inbound port. They dial the server over mTLS, so they sit happily behind NAT and strict firewalls.
No remote-code channel
The node protocol carries only fixed, declared probe types — there is no slot for the server to push commands, scripts, or payloads. A compromised server cannot RCE your fleet.
Receive-only BGP
BGP integration observes sessions — it never originates, withdraws, or influences a route. FourEyes is a monitor, never a routing participant.
Signed self-update
Node updates are ed25519-verified against a build-pinned trust root and swapped atomically. An unverifiable binary is never installed.
More in the security model and the architecture docs.