# Hosted realms: AIRC for laptops, dynamic IPs and people without a domain

*Design note, 2026-09-26. Not built.*

## 1. The problem

The endorsed way to be on AIRC is to own a domain, run `aircd`, publish two
DNS records, and open port 2472. That is right for an organisation with a
server. It excludes most individuals: a developer with a laptop in a café is
behind carrier-grade NAT, has an address that changes hourly, and owns no
domain. Their agents should still be able to send and receive.

Rafael's framing: could a service, say `airc.dev`, let anyone register an
AIRC presence (`joes-laptop.airc.dev`, or a "workspace") so that messages
reach the laptop, ideally without `airc.dev` carrying the traffic?

## 2. How this problem is normally solved

Four families, each used by systems you know:

| approach | examples | what it needs from the user's network | who carries the bytes |
|---|---|---|---|
| **Dynamic DNS** | DynDNS, DuckDNS, Cloudflare API | an inbound port that is actually reachable | nobody but the two ends |
| **NAT traversal** | WebRTC (STUN/ICE/TURN), Tailscale (DERP), libp2p (hole punching + relay) | nothing, but needs a signalling server, both sides online at once, and a relay fallback for the 10–20 % of NATs that cannot be punched | direct when it works, a relay when not |
| **Reverse tunnel** | ngrok, Cloudflare Tunnel, `ssh -R`, Tailscale Funnel | nothing: the laptop dials out and keeps the connection open | the tunnel service |
| **Home server** | email, XMPP, Matrix, IRC bouncers | nothing: the laptop is a *client* of a server that is always on | the home server |

Dynamic DNS alone fails the café case: the record can be perfect and the
inbound connection still dies at the NAT. NAT traversal solves it but at the
cost of a signalling protocol, candidate gathering, simultaneous
connectivity, and a relay anyway for the unpunchable cases; it is the right
tool for a video call, where the bytes are heavy and latency-sensitive, and
the wrong tool for short text messages between agents that are often not
online at the same time. Reverse tunnels and home servers are the same idea
seen from two ends: an always-on party the laptop dials *out* to.

Every messaging protocol that lasted picked the home-server model, because
it also solves the problem NAT traversal does not: **the recipient is
offline**. A store-and-forward server is what makes "send now, read
later" work, and AIRC already has that server.

## 3. What fits AIRC

AIRC already assumes servers see message bodies; that is why origin
authentication is per message and why policy runs at the server. So an
`airc.dev` that carries Joe's messages is not a new trust concession; it is
one more realm operator, and Joe's agents are its clients. The design then
falls out of what exists:

### 3.1 A hosted realm with a remote client face

`airc.dev` runs an ordinary `aircd` for the realm `airc.dev`. Today a
client face is a Unix socket and identity comes from the connecting uid
(§5 of the spec). A hosted realm needs a **remote client face**: a TLS
listener on which a client proves who it is without a uid. Two ways, both
reusing machinery the spec already has:

- **Workspace key.** Joe's laptop generates an ed25519 key once (the same
  kind a realm has). Registration binds the public key to a namespace:
  `airc.dev` records `key K → namespace joe`. The client's `hello` carries
  `ns: ["joe"]`, a `nonce`, a `ts` and a `sig` over
  `"airc-client-hello\n<realm>\n<ns>\n<ts>\n<nonce>"` (the client-side twin
  of §9.4). The server verifies against the registered key and answers
  `welcome.ns: ["joe"]`. No passwords, nothing to leak in transit, and the
  same key can later make Joe's laptop a real realm of its own (§4).
- **Bearer token** for environments that cannot hold a key. Simpler, weaker,
  optional.

From there Joe runs exactly what a fleet runs today: `airc relay
--namespace joe` with a backend for his agent runtime, connecting *out* to
`airc.dev:2473` over TLS instead of to a local socket. It binds `joe/`,
receives, acks. When the laptop sleeps, messages to `//airc.dev/joe/…` are
spooled at `airc.dev` and delivered when the relay reconnects; the sender
sees `queued`, then it arrives. Links and passports work unchanged, because
they are per endpoint, not per host.

Names: `//airc.dev/joe/reviewer`. One realm, one key, one SRV record, one
policy file; workspaces are namespaces. Vanity subdomains
(`//joe.airc.dev/reviewer`) are a wildcard SRV pointing at the same server
plus a rewrite, and can come later.

### 3.2 What `airc.dev` provides

- An `aircd` with the remote client face, TLS, and the realm's key in DNS.
- A registration API: create a workspace (namespace), register or rotate a
  workspace key, delete. Rate-limited, abuse-reportable, with a policy
  default that nothing outside the workspace's own links and passports can
  reach it (default-deny plus links, as recommended for any realm).
- Optionally, **managed DNS for people who do have a reachable port** (§4).

It is a conduit for those who need one and a directory for those who do not.

### 3.3 Cost and scale

Per idle workspace: one TLS connection and one spool directory. Per
message: one signature verification (the sending realm's), one policy check,
one write. A single small server handles tens of thousands of idle
workspaces; the Python reference implementation is single-core and would be
the first thing to replace with the planned C++ service, but the shape does
not change.

## 4. Direct connections, when they are possible

Some users are not in a café: a home server on a residential connection with
a dynamic IP and a forwardable port. For them `airc.dev` can be **only DNS**,
which is the "return the real address" idea done the way DNS already does
it:

- Joe registers `joes-house` and receives credentials to update records
  under `joes-house.airc.dev`.
- His server runs `aircd` for the realm `joes-house.airc.dev` with its own
  key, and a small updater keeps `_airc._tcp.joes-house.airc.dev SRV` and the
  A record current (dynamic DNS), while `_airc.joes-house.airc.dev TXT`
  carries his key.
- Peers resolve and dial him directly; `airc.dev` never sees a message.

This is a real realm in every sense; `airc.dev` is a registrar. The two
modes share the registration API, and a workspace can move from hosted to
direct by publishing records without changing its key.

## 5. The hybrid, if it is ever wanted

A hosted workspace could *advertise* candidate direct addresses in its
`welcome`/registry, and a peer could try them with the usual TLS plus
signing before falling back to the hosted path. That is the NAT-traversal
family again, and it only pays off when direct connectivity is likely (two
laptops on the same LAN, a server with a port). It is compatible with
everything above and not needed for the first version. If it is ever built,
it should be done as in libp2p: the hosted connection stays the control
channel, the direct one is an optimisation that can drop at any time.

## 6. What this needs in the spec and the reference implementation

1. **Remote client face** (`client_tls: host:port`, with `tls.cert/key`),
   identity from a signed client hello against a `key → namespaces` table
   (`client_keys` in config, or a registry the API writes). About the size
   of the peer authentication work.
2. **`airc relay --server airc.dev:2473 --key ~/.airc/workspace.key`**: the
   relay dials TLS, signs its hello, reconnects with backoff; `airc send`
   likewise for one-shot sends from a hosted client.
3. **Registration API** on `airc.dev`: HTTPS, create/rotate/delete
   workspace, and for direct mode the dynamic-DNS update endpoint. Outside
   the protocol; a small service beside `aircd`.
4. **Spec**: a §5 addition for key-authenticated client hello; a note that a
   realm MAY host namespaces for remote clients; nothing else changes.

## 7. End-to-end privacy, separately

A hosted realm reads bodies, like today's local server does. If people want
`airc.dev` not to, the answer is end-to-end encryption of the body between
endpoints (each endpoint publishes a key through its realm; the sender
encrypts `body` to it and sets `type` accordingly). Servers route the same
envelope and cannot read it; links, passports and policy still work on the
envelope. That is a feature for any realm, not specific to hosting, and it
is the right place to spend the effort that NAT traversal would have cost.
