CADS-Tunnel docs
How-to

Run redundant agents for high availability

A real, tested capability (issue #8) that wasn’t documented anywhere on this site: run two or more ct-agent processes for one tunnel, sharing a single identity, so the tunnel survives one agent (or its host) dying. The edge tracks every agent registered for a routing token and routes to the most recent, failing over to a survivor when one drops.

The one rule: share the identity, not just the origin

Redundant agents must present the same routing token and the same origin key — that’s what makes the edge treat them as interchangeable servers for one tunnel rather than two separate tunnels. Point every instance at the same CT_AGENT_ORIGIN_KEY and CT_AGENT_CAPABILITY_OUT paths on a volume all instances can read. The first agent to start generates and persists that identity; every later one loads it instead of generating its own — so bring up the primary first and let it finish before starting the others.

# agent 1 (primary — creates the shared identity)
CT_AGENT_JOIN_TOKEN=<token> CT_AGENT_ORIGIN_KEY=/shared/origin.key \
CT_AGENT_CAPABILITY_OUT=/shared/capability.bin CT_AGENT_ORIGIN=127.0.0.1:8081 \
  ct-agent onboard

# agent 2+ (redundant — load the same identity, same origin)
CT_AGENT_JOIN_TOKEN=<token-2> CT_AGENT_ORIGIN_KEY=/shared/origin.key \
CT_AGENT_CAPABILITY_OUT=/shared/capability.bin CT_AGENT_ORIGIN=127.0.0.1:8081 \
  ct-agent onboard

Each instance still needs its own single-use CT_AGENT_JOIN_TOKEN to onboard — sharing the origin identity isn’t the same as sharing the onboarding credential.

What actually happens on failover

Confirmed real and currently passing — ct-edge’s own test suite (cargo test -p ct-edge redundant_agents, re-run hermetically for this page: 1 passed; 0 failed) exercises exactly this: multiple agent registrations for one token, the edge routing to the most recent, and — on that registration dropping — failing over to a survivor while evicting only the dropped registration, never the others.

For a full live rehearsal against a running deployment, scripts/redundancy-smoke.sh (in the CADS-Tunnel repo) brings up one origin and two agents on one identity, confirms a real client round-trip, kills the serving agent, and re-confirms the client still gets through off the survivor. Not run against production for this page — it needs its own control-plane

Keep the shared origin.key file owner-only — it’s your origin’s static Noise private key, the thing that makes possession of your Capability sufficient to be trusted as your origin. Every redundant agent needs read access to it, and nothing else should.

See also

ct-agent CLI commands and Environment variables (core tunnel) for CT_AGENT_ORIGIN_KEY and the related CT_AGENT_ORIGIN_KEY_DIR (used for zero-downtime origin-key rotation — a related but distinct procedure: swapping which key an already-redundant or single agent serves, without breaking clients mid-flight).

Found an error, or something that didn't work as documented? Open an issue →