Architecture
Three server-side components and one agent. The control plane never sees plaintext — it distributes public keys and policy, and relays ciphertext.
Components
- management — gRPC
:50051for agents, HTTPS:8080for the REST API and dashboard. Stores peers, groups, ACLs, routes and setup keys in PostgreSQL, or in memory for development. - signal —
:10000. Routes ICE negotiation between peers and carries the always-on packet relay. - relay — STUN/TURN on
:3478, used to discover and hold open a direct path. - agent — on every device. WireGuard, Magic DNS, ACL enforcement, routing.
How a peer connects
- It enrolls with management using a setup key and receives a stable
100.64.0.0/10address, then opens a long-lived sync stream for peer, group, route and ACL updates. - For every other peer it opens a signal stream. WireGuard packets are relayed peer-to-peer through the signal server by default, which works behind any NAT with no port forwarding.
- In parallel it runs ICE to try for a direct path, and switches to it only once repeated full-size probes come back answered.
Relay first, direct second
ICE connecting is not the same as traffic being able to flow. A peer is promoted to the direct path only after several consecutive full-size probes succeed, and a single missed probe drops it back to the relay with exponential backoff.
This is deliberate. Some NAT bindings pass small packets while dropping real traffic, so a path that answers one probe can still black-hole data — and a link that promotes eagerly oscillates instead of settling.
The data path
WireGuard → RelayBind → peerLink → relay (default)
└─────────→ direct ICE (once proven)Both directions terminate in the same WireGuard device, so promotion and demotion are invisible to anything above it — an application sees one continuous connection.
Enforcement points
ACLs are applied by the receiving peer, not the sender, so policy holds even if a peer is compromised: on Linux through an ordered iptables chain, on Windows through an in-process filter on decrypted packets, and on netstack peers in the userspace forwarder.