Federation
Federation lets two or more gatewayd instances act as a coordinated group. Each peer keeps its own SQLite (no shared database), but selected configuration kinds — policies, devices, privacy classes, DNS rules, presets — can be pushed from one peer to another or pulled by a peer from a designated primary.
This is how you run “the home gateway” and “the VPS bridge” as a single logical thing without operating two unrelated control planes.
How peers exchange config
Section titled “How peers exchange config”Federation isn’t a “node is primary” / “node is secondary” model. It’s per peer, per direction. Each peer relationship has three knobs:
| Field | Values | Meaning |
|---|---|---|
sync_policy |
none / push / pull / bidirectional |
The direction this peer relationship operates in. none disables sync between this pair. |
sync_resources |
CSV of kind keywords | The outgoing allowlist — which kinds this node may push to (or share with) the peer. |
allowed_receive_resources |
CSV of kind keywords | The incoming allowlist — which kinds we accept from this peer. Empty = accept all (legacy). |
Kind catalog (GET /api/v1/federation/resources): bridges, routing, dns, devices, profiles, tunnels, segments, settings, nodes.
So “node X is the primary for routing across the cluster” is shorthand for: every peer relationship has sync_policy: push with sync_resources: routing from X’s side, and allowed_receive_resources: routing from the other side.
Three-node example: the office Pi pushes routing and dns to two VPS peers; the VPS peers don’t push back. Each VPS still owns its own tunnels config locally — because tunnels isn’t in the office Pi’s sync_resources, it never gets overwritten.
The federation_roles table is a separate labelling taxonomy for an operator’s own bookkeeping (role_type ∈ {standalone, hub, spoke, relay, observer}, trust_level, sync_policy). It documents intent for the dashboard; the actual sync gating comes from the peer-relationship fields above.
Tunnel between peers
Section titled “Tunnel between peers”Federation does not stand up its own dataplane tunnel. It piggybacks on whatever connectivity is already there — typically the mesh WireGuard tunnel between the two nodes, or a TLS-fronted REST connection. Peer setup:
- On the primary, register the peer:
POST /api/v1/nodeswith the peer’s mesh address and an API key. - The two sides exchange signing keys via
POST /api/v1/nodes/exchange— that’s what authenticates federation messages. - Operator-side approval:
POST /api/v1/nodes/{id}/approve. - From that point, federation requests carry signed manifests over the existing channel; no separate peer tunnel is provisioned.
If the underlying mesh tunnel breaks, federation pauses; it doesn’t try to repair connectivity itself.
Config sync
Section titled “Config sync”Sync happens through two paths:
- Operator-triggered push / pull —
POST /api/v1/federation/sync(or the UI’s Sync now button) walks the peer list and pushes / pulls the configured object kinds. This is what operators use after a config change. - Auto-sync prober — each peer can have a
sync_interval_seconds. When set, a background prober runs against that peer on the cadence. Useful for keeping a standby continuously fresh.
Pushed and pulled changes are applied atomically at the storage layer: a partial sync never leaves the secondary in an inconsistent state.
Conflicts (e.g. a local edit on the receiving peer that collides with an incoming push) are resolved by last-writer-wins, with the overwritten row logged to the audit trail so you can see what was replaced.
Use it for
Section titled “Use it for”- Home + remote VPS — the home Pi pushes device + routing + dns; the VPS pulls. Same rules apply at home or on the road; the VPS keeps its own tunnels local.
- Warm standby — two boxes with bidirectional
routingsync; the standby’ssync_resourcesexcludes anything the standby is supposed to own (its ownnodesrow, its own logs). If the active fails, point your LAN’s gateway IP at the standby and policies are already in place. (The VIP / failover mechanism itself is outside The Gateway’s scope —keepalivedor a similar tool handles that part.) - Multi-site — three offices, each with its own gateway. A central admin Pi (or a VPS) pushes
routinganddnsto each site; each site’s gateway never hastunnelsin itsallowed_receive_resources, so its local outbound config stays site-specific.
API surface
Section titled “API surface”Federation has two endpoint families: status/control under /federation/, and the underlying peer/node lifecycle under /nodes/.
| Method | Path | Purpose |
|---|---|---|
GET |
/api/v1/federation/status |
Federation health snapshot |
GET |
/api/v1/federation/peers |
List known federation peers (read-only) |
GET |
/api/v1/federation/manifest |
Authoritative manifest the primary advertises |
GET |
/api/v1/federation/inventory |
Per-peer inventory snapshot |
GET |
/api/v1/federation/recent-events |
Recent federation event log |
POST |
/api/v1/federation/sync |
Force a sync with one peer; body {peer_url: "..."} |
GET/POST/PUT/DELETE |
/api/v1/federation-roles |
Per-kind role table (top-level, hyphenated) |
GET/POST/DELETE |
/api/v1/nodes |
Peer node lifecycle (create / list / remove) |
POST |
/api/v1/nodes/exchange |
Exchange signing keys with a new peer |
POST |
/api/v1/nodes/{id}/approve |
Approve a pending peer |
POST |
/api/v1/nodes/{id}/connect |
Initiate a connection attempt |
Next steps
Section titled “Next steps”After peers are exchanged and approved:
- Set per-peer allowlists deliberately. Each peer’s
sync_resources(out) andallowed_receive_resources(in) decides which kinds flow. Empty receive-side = accept-all, which is rarely what you want — set them explicitly even if you have to repeat the same list. - Audit recent federation events monthly.
GET /api/v1/federation/recent-eventsplus/federation/overviewsurface drifting peers and conflict events (every overwrite from an incoming push is logged). Conflicts indicate two operators editing the same kind in different places — agree on which peer’s allowlist that kind belongs to. - Keep backup separate. Federation is not a backup — if the primary applies a bad policy, secondaries cheerfully replicate it. Snapshot independently.
- Don’t expose secondaries to operators by mistake. A secondary that someone edits “just this once” turns into a primary-by-confusion. Lock UI access by role.
Related
Section titled “Related”- Mesh networking — federation typically runs over a mesh tunnel.
- Backup — federation is not a backup; take snapshots independently.
- Use case: hybrid home lab — Pi pushes routing/dns/devices to a VPS, VPS keeps its own tunnels.