Skip to main content

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
Configure STUN servers in ~/.atlas/state/config.toml:
[stun]
servers = ["stun.l.google.com:19302"]
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

1

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.
2

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.
3

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.
4

Handshake and forward

The standard Atlas handshake runs through the relayed connection. Once authenticated, all application messages flow through the relay. The relay forwards raw bytes without inspecting or decrypting the content.
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:
  1. Tries direct dial to all known addresses for the target
  2. Falls back to relay if direct dial fails and enable_relay is true
  3. Tries each configured relay in order until one succeeds
The connection path (direct or relay) is shown in command output:
Connected to node_a1b2c3...
my-peer [verified via direct]

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:
[network]
relays = ["198.51.100.50:4433"]

[transport]
enable_relay = true
offer_relay = false
relay_bandwidth_limit = 1048576
KeyDefaultDescription
network.relays[]Relay node addresses to register with
transport.enable_relaytrueAllow using relays as a client (fallback when direct dial fails)
transport.offer_relayfalseOffer to act as a relay for other peers
transport.relay_bandwidth_limit1048576Maximum bytes per second forwarded when acting as a relay (1 MB/s)
Setting offer_relay = true requires enable_relay = true. The config validator will reject configurations where relay offering is enabled but relay support is disabled.

Error handling

If the relay cannot pair two peers, it responds with a RelayError message containing the reason. Common errors:
  • Target peer is not registered with the relay
  • Relay is at capacity
  • Handshake timeout (default: 10 seconds)
When a relay error occurs, Atlas tries the next relay in the list. If all relays fail, the connection attempt returns an error.