Skip to content

Tunnel Protocol

atreoAGENT maintains a persistent connection to atreoLINK for real-time coordination. This control tunnel carries ACL updates, WireGuard client provisioning, and device management. It’s never used for user traffic. App traffic flows over a separate WireGuard tunnel that’s established directly between each client and the agent.

The tunnel uses WebSocket (WSS) as the sole transport. On connection failure the agent reconnects with exponential backoff. The connection is authenticated with the device token from pairing, sent as a query-string parameter on the upgrade.

Every state-changing message from atreoLINK to the agent is wrapped in a signed envelope:

{
"type": "<message-type>",
"correlationId": "<uuid, optional>",
"payload": { ..., "intent": "...", "ts": 1234567890 },
"signerId": "owner | <memberId>",
"signature": "<base64 Ed25519 over canonical-JSON(payload)>"
}

The agent verifies every envelope before applying it:

  • signerId == "<memberId>" → verified against that member’s identityKey from the agent’s ACL.
  • The payload’s intent string is built from <commandName>-<binding-fields>-<unixSeconds> and must match what the agent expects for this command.

atreoLINK never sees the signing keys, and cannot synthesise or modify signed envelopes; it relays the bytes verbatim.

Some authorisations represent ongoing state rather than a one-shot command: who is a member, which apps exist, an active custom domain. atreoLINK stores the latest user-signed envelope per entity and dimension and assembles them into a single signed DeviceState that it pushes to the agent on connect and on every change (see Connection lifecycle).

State mutation (cloud to agent, envelope-signed)

Section titled “State mutation (cloud to agent, envelope-signed)”
Message Signer Description
member:added inner attestation Add a member. Carries the original join attestation (ownerSig + acceptanceSig); the agent verifies the chain against the pinned owner identity and the invite token’s derived public key.
member:removed owner Remove a member; agent reconciles WireGuard peers.
member:permissions owner Update which apps a member can reach.
member:status owner Suspend or re-activate a member without removing them.
member:left member (self) Member-initiated leave.
client:removed owner or member Remove a WireGuard client. Either authority can sign.
app:upserted owner Add or update an app definition.
app:removed owner Remove an app from the catalogue.
device:unpaired owner Kill switch; agent wipes config and re-enters pairing mode.
device:custom-domain-set owner Activate a custom domain; agent issues the wildcard cert.
device:custom-domain-cleared owner Deactivate a custom domain.
notify:apikey owner Read the current notification API key.
notify:apikey:rotate owner Mint a new notification API key.
Message Signer Description
wg:challenge member Client requests a challenge nonce; agent returns a 32-byte nonce with 5-minute validity.
wg:provision member Client sends the signed nonce plus its WireGuard public key. Agent verifies the envelope against the member’s pinned identity, allocates a tunnel IP, adds the peer, and signs the response transcript (covering server pubkey, tunnel IP, endpoint, allowed IPs, and keepalive) with its long-term identity key.

Agent to cloud (responses and unsolicited)

Section titled “Agent to cloud (responses and unsolicited)”
Message Description
wg:provision:response Provisioning result, including the agent’s identity signature over the response transcript.
wg:challenge:response Nonce returned to the client.
device:endpoints Signed envelope listing LAN candidates and DDNS hostnames. Mobile clients verify the signature against the agent’s pinned identity before trusting any endpoint candidate.
device:metadata Reports the proxy HTTPS port to the cloud on every reconnect.

Notification delivery does not use the control WebSocket. The agent sends each notification to atreoLINK via HTTP, with end-to-end-encrypted ciphertexts addressed to the recipient’s identity key. atreoLINK fans out to that member’s paired devices and browsers using push tokens it holds — the agent isn’t involved in pairing and has no per-device state. See Per-device delivery, Encryption, and the Notification API for the full flow.

  1. The agent connects to atreoLINK’s WebSocket endpoint with its device token in the query string.
  2. A 25-second ping keeps the connection alive (below NAT/CGNAT idle timeouts).
  3. On disconnect, the agent reconnects with exponential backoff.
  4. On connect, atreoLINK pushes a complete signed DeviceState: the latest user-signed envelope for every member, app, and active custom domain. It pushes a fresh DeviceState again on every change. The agent verifies each item against the pinned owner identity. One-shot commands are delivered live as they happen.
  • Transport. All tunnel messages travel over TLS (WSS).
  • Envelope signing. Every state-changing message carries an Ed25519 signature over canonical-JSON of the payload. The agent verifies each signature against the pinned owner identity or the member’s ACL identityKey before applying any change.
  • Intent binding. The payload’s intent field ties the signature to a specific command, target, and (for fresh commands) timestamp. Replay or repurposing of a captured signature is rejected.
  • No execute-on-agent capability. The agent only acts on the typed messages above. atreoLINK cannot ask the agent to run arbitrary code.
  • No access to key material or content. atreoLINK never sees signing keys, push plaintexts, or any user identity private material; it relays signed envelopes byte-for-byte. It does store and forward the coordination metadata those envelopes carry — ACL state, app definitions, active custom domains — but it can neither read your traffic nor forge a command.

See Authentication for how envelopes interact with identity pinning, and Encryption for the underlying primitives.

WireGuard is a registered trademark of Jason A. Donenfeld.