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)”
MessageSignerDescription
member:addedinner attestationAdd 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:removedownerRemove a member; agent reconciles WireGuard peers.
member:permissionsownerUpdate which apps a member can reach.
member:statusownerSuspend or re-activate a member without removing them.
member:leftmember (self)Member-initiated leave.
client:removedowner or memberRemove a WireGuard client. Either authority can sign.
app:upsertedownerAdd or update an app definition.
app:removedownerRemove an app from the catalogue.
device:unpairedownerKill switch; agent wipes config and re-enters pairing mode.
device:custom-domain-setownerActivate a custom domain; agent issues the wildcard cert.
device:custom-domain-clearedownerDeactivate a custom domain.
notify:apikeyownerRead the current notification API key.
notify:apikey:rotateownerMint a new notification API key.
MessageSignerDescription
wg:challengememberClient requests a challenge nonce; agent returns a 32-byte nonce with 5-minute validity.
wg:provisionmemberClient 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)”
MessageDescription
wg:provision:responseProvisioning result, including the agent’s identity signature over the response transcript.
wg:challenge:responseNonce returned to the client.
device:endpointsSigned envelope listing LAN candidates and DDNS hostnames. Mobile clients verify the signature against the agent’s pinned identity before trusting any endpoint candidate.
device:metadataReports 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.