Whisper · Docs
Infrastructure

Two servers, one truth

The worst failure mode for identity infrastructure isn't "the nameserver is down" — it's "the nameserver is up, but lying to half your traffic."

One authoritative server is a single point of failure; a lazily-replicated second one is worse, because now there are two answers and no way to know which is current. Whisper runs two authoritative servers, both live, both taking queries, and for any given question they return the same answer, byte for byte — not eventually, and not "usually."

Why naive replication isn't good enough for identity

A classic primary/secondary DNS setup already tolerates a dead server: if the primary disappears, the secondary keeps answering from its last transfer. That's fine for a static zone that changes twice a year. It's not fine for agent identity, where records are created and torn down continuously and a client's trust decision depends on all of them agreeing at once.

Consider a stale secondary against DANE (TLSA, RFC 6698; see DANE & TLSA): a client resolves the AAAA from one server and the TLSA pin from the other. Captured on either side of a write — the address just allocated, the key not yet replicated, a revoked identity's PTR gone on one node but not the other — and the client either fails a connection that should have worked, or worse, succeeds against stale trust data.

A partially-converged pair of nameservers is a covert channel for exactly the identity confusion Whisper exists to prevent. So the bar isn't "eventually consistent." It's: at any instant, either server answers the current truth, or it fails closed by not answering at all — never a partial or stale truth.

Byte-identical, active/active — verify it yourself

Both ns1.whisper.online and ns2.whisper.online are authoritative for agents.whisper.online (the forward zone) and for the delegated ip6.arpa ranges under 2a04:2a01::/32 (AS219419). Neither is a read replica serving stale cache; both hold the current zone and answer identically.

With stock tools — ask both servers the same question and diff:

diff <(dig +noall +answer @ns1.whisper.online AAAA acef2002a323d40d4.demo.agents.whisper.online) \
     <(dig +noall +answer @ns2.whisper.online AAAA acef2002a323d40d4.demo.agents.whisper.online)
# no output — the two answers are identical, including the TTL
kdig +dnssec @ns1.whisper.online -x 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4
kdig +dnssec @ns2.whisper.online -x 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4
# same PTR, same RRSIG validity window, same AD=1

With Whisper — the same guarantee, but you never have to think about which node you hit:

whisper verify 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4

whisper verify (and the keyless curl https://rdap.whisper.online/verify-identity/<addr>) resolves through whichever server the client's resolver picked — there's no "prefer the primary" flag anywhere in the tooling, because there's no primary to prefer.

The mechanism: SOA, NOTIFY, AXFR/IXFR

Under the hood this is unglamorous, decades-old DNS — the same machinery that has synchronized secondaries since RFC 1035. Every zone carries an SOA record whose RDATA (RFC 1035 §3.3.13) is the whole story:

agents.whisper.online. 900 IN SOA ns1.whisper.online. hostmaster.whisper.online. (
        1783326316   ; serial  — bumps on every zone change
        7200         ; refresh — how often a secondary checks
        3600         ; retry   — backoff if a refresh fails
        1209600      ; expire  — when to stop answering if it can't refresh
        300 )        ; minimum — negative-cache TTL

The serial is the whole synchronization contract: two servers agree once their serials match, full stop. Comparisons use serial-number arithmetic mod 2³² (RFC 1982) so the counter can wrap without ever appearing to go backward. When a write lands, the serial ticks up and the writing node sends a NOTIFY (RFC 1996) to its peer instead of waiting out the two-hour refresh timer above — that's what turns "eventually, whenever the peer next polls" into "within milliseconds." The peer then pulls the delta by zone transfer: IXFR (RFC 1995) for an incremental diff when both sides share transfer history, falling back to a full AXFR (RFC 5936) when it doesn't. Transfers ride the same TSIG-authenticated channel either server would use with any secondary — no bespoke replication protocol, one mechanism, well-understood by every DNS operator on earth.

Each node applies the incoming transfer as an atomic zone swap: the updated zone is assembled in full, off to the side, and only pointed to as the live answer once it's completely built. There is no window where a query landing mid-transfer sees half the new records and half the old ones — a lookup either hits the previous complete zone or the next complete one, never a hybrid.

Compare serials yourself, or let Whisper skip the step:

# stock tools — you check parity by hand
dig +short SOA @ns1.whisper.online agents.whisper.online
dig +short SOA @ns2.whisper.online agents.whisper.online
# ns1.whisper.online. hostmaster.whisper.online. 1783326316 7200 3600 1209600 300
# ns1.whisper.online. hostmaster.whisper.online. 1783326316 7200 3600 1209600 300  <- match
# with whisper — you never have to: see the convergence guarantee below
whisper agent create --name shipping-bot
# returns only once BOTH serials already carry this agent's records

Read-your-writes: the convergence barrier

Ordinary DNS replication is asynchronous by design — NOTIFY/AXFR narrows the propagation window, it doesn't eliminate it. Whisper adds one guarantee on top: a write to the control plane does not return as done until every authoritative node can already answer for it. Register an agent via whisper.agents({op:'register', args:{label:'shipping-bot'}}) (see Control plane) or whisper agent create, and the moment the call returns, the address, its reverse PTR, its forward AAAA, and its TLSA pin all resolve identically from ns1 and from ns2 — not "probably by now," but proven before the response left the server. There is no interval, however small, in which the identity exists on one node and is invisible on the other.

That barrier is bounded, and it fails open rather than hanging: if a peer is briefly unreachable, the write waits up to a fixed deadline for it to catch up, then completes anyway rather than blocking registration on an outage. Redundancy is there to survive a dead node, not to make every write hostage to one.

# stock tools: query both nodes the instant `create` returns
# (proof-bot lands under YOUR tenant subdomain, not the public demo/)
whisper agent create --name proof-bot
dig +short AAAA proof-bot.<tenant>.agents.whisper.online @ns1.whisper.online
dig +short AAAA proof-bot.<tenant>.agents.whisper.online @ns2.whisper.online
# both already answer — no retry loop, no propagation delay to poll for

Two names, ns1.whisper.online and ns2.whisper.online, are both listed as NS for the zone — see Underneath the hood: how DNS actually resolves you for the full delegation chain from the root down. Either one failing to answer simply leaves the resolver to retry the other; nothing downstream needs to know which one is currently healthy.

Next

DANE & TLSA — why identical zone state on both nodes is what makes DANE pinning safe to rely on. Graph-first resolution — what happens on the query path when the graph, not the authoritative zone, has the opinion.