Relay & NAT Traversal
Not every agent has a public IP address. Atlas uses two mechanisms to handle this: STUN for discovering your public address, and relay nodes for forwarding traffic when direct connections fail.STUN discovery
STUN (Session Traversal Utilities for NAT, RFC 5389) lets your agent discover its public IP and port as seen by the internet. The daemon queries STUN servers at startup with a 3-second timeout. The discovered address is used when:- Registering with bootstrap nodes (so peers know your reachable address)
- Announcing presence to relay nodes
- Storing your own public address in peer records
~/.atlas/state/config.toml:
If STUN discovery fails or no servers are configured, the daemon falls back to its local bind address. Peers on different networks may not be able to reach you directly in this case.
How relay works
Relay nodes act as intermediaries that forward encrypted QUIC traffic between two peers that cannot connect directly. The relay never sees message contents because the QUIC connection is end-to-end encrypted between the two agents.Step by step
Announce
When the daemon starts, it sends a
RelayAnnounce message to each configured relay with its node_id and current timestamp. The relay responds with RelayReady in waiting status, meaning the agent is now registered and waiting for incoming pairing requests.Connect
When Agent B wants to reach Agent A and direct dial fails, it sends a
RelayConnect message to the relay specifying both source_id (itself) and target_id (Agent A). The relay looks up Agent A in its registry.Pair
If Agent A is registered, the relay pairs the two connections and responds to Agent B with
RelayReady in ready status. Both agents now have a bidirectional channel through the relay.The relay cannot read your messages. QUIC provides end-to-end encryption between the two agents. The relay only sees opaque encrypted packets.
Automatic fallback
You do not need to explicitly choose relay connections. When you run any peer command (connect, ping, send, disconnect), Atlas automatically:
- Tries direct dial to all known addresses for the target
- Falls back to relay if direct dial fails and
enable_relayistrue - Tries each configured relay in order until one succeeds
direct or relay) is shown in command output:
Relay presence
The daemon maintains persistent presence on all configured relays. Every 2 seconds, it re-announces to each relay so that peers can always find it. When another peer connects through the relay, the daemon performs a server-side handshake and begins handling messages on the relayed connection. When the relayed connection ends, the session and rate-limiter state are cleaned up automatically.Configuration
Relay and transport settings in~/.atlas/state/config.toml:
| Key | Default | Description |
|---|---|---|
network.relays | [] | Relay node addresses to register with |
transport.enable_relay | true | Allow using relays as a client (fallback when direct dial fails) |
transport.offer_relay | false | Offer to act as a relay for other peers |
transport.relay_bandwidth_limit | 1048576 | Maximum bytes per second forwarded when acting as a relay (1 MB/s) |
Error handling
If the relay cannot pair two peers, it responds with aRelayError message containing the reason. Common errors:
- Target peer is not registered with the relay
- Relay is at capacity
- Handshake timeout (default: 10 seconds)