Connecting two machines privately over the internet usually means running infrastructure: a VPN with an open port, a coordination service that keeps a membership list, or a relay network that routes the traffic. Each of those components is observable from the outside, blockable by network operators, and a target.
Trantor's question is simpler: how do we let Alice reach her server without anyone else seeing where the server is, what runs on it, or even that the server exists? The whole protocol is built around making that answer hold for every observer who isn't holding the right passphrase.
Three actors, three flows. The server publishes its connection details (encrypted) into the public DNS once. The client resolves them on demand. The browser then talks directly to the server over plain HTTPS — there is no broker on the path.
The server publishes once. The client resolves on demand. The browser talks directly to the server.
Here is what happens, in order, when a user types https://foo.bar.com in their browser. The diagram shows the eight steps on a timeline; the list below it gives the details — the cryptographic primitive used at each step, and what an outside observer can see.
Eight steps, two DNS lookups, no infrastructure beyond DNS itself.
DNS query intercepted
The browser issues an ordinary DNS query for foo.bar.com. Terminus, hooked into the OS DNS layer, sees it before any external resolver does.
Observable from outside: nothing — the query never leaves the user's machine yet.
Phase 1 lookup
Terminus computes hash = Argon2id(user passphrase, hostname, 16 MB), encodes it with Base62, and sends a TXT lookup for hash(foo.bar.com).
Observable from outside: a TXT lookup that looks like any SPF / DKIM / DMARC query.
Master passphrase recovered
The DNS authority returns one encrypted record. Terminus derives the AES key with Argon2id(passphrase, hostname, 64 MB), runs AES-256-GCM, and unwraps the master passphrase.
Observable from outside: ciphertext only — same shape as any TXT response.
Phase 2 lookup
With the master in hand, Terminus computes a new hash = Argon2id(master passphrase, hostname, 16 MB) and queries TXT for hash(foo.bar.com) — a totally different label.
Observable from outside: another TXT lookup, no link visible to the first one.
Connection records recovered
The DNS authority returns several encrypted TXT records. Terminus decrypts each one and extracts the server's IP (v4 / v6), the private key of the TLS certificate (32-byte P-256 scalar), and (if present) the ECH config used to encrypt the SNI.
Observable from outside: a handful of TXT responses, all ciphertext.
Build the certificate locally
Terminus rebuilds the TLS certificate byte-for-byte the way the server holds it. The private key it just decrypted, plus deterministic fields known on both sides — NotBefore = first day of the current month, Serial = SHA-256(master ‖ hostname ‖ NotBefore)[:8], signature using deterministic ECDSA (RFC 6979) — guarantee the same bytes on both ends. Shipping the private key in the DNS record (rather than the public key) means the client doesn't have to derive anything from a separate share: it has the signing material directly. The result is injected into the OS trust store; the ECH config is cached for local use.
Observable from outside: nothing — pure local computation.
TLS handshake to the server
The browser opens a TLS connection straight to the server's IP. If the browser supports ECH, the SNI is encrypted using the config Terminus served locally — the destination hostname never appears on the wire.
Observable from outside: a TLS ClientHello to an IP, possibly with an encrypted SNI. Standard HTTPS shape.
Connection established
The server presents the same certificate Terminus just forged — the public key matches, the trust store has it, the handshake succeeds. From now on, the traffic is end-to-end-encrypted HTTPS.
Observable from outside: indistinguishable from any other HTTPS site.
Two design choices in this flow are worth pausing on. Why two DNS lookups? If a single record held the connection details directly, revoking a user passphrase would force re-encrypting and republishing every record. With two phases, each user passphrase has its own first-phase record (the one that maps to the master); revoking it means deleting that one record and rotating the master, leaving everyone else untouched. Why ship the cert's private key in the DNS record? Because the goal is byte-for-byte cert agreement between client and server, with no certificate authority. Sending the private key (rather than just the public key plus shared parameters) removes any room for ambiguity: client and server sign the same TBSCertificate with the same key under deterministic ECDSA (RFC 6979), and produce the exact same certificate bytes — every time.
Trantor protects up to three layers of a connection, in concentric order. The inner layers are always covered; the outer layer (SNI) requires browser-side ECH support to be hidden from passive observers.
Levels 1 and 2 are always on. Level 3 turns on when the client browser supports ECH.
Trantor uses standard, well-vetted primitives — no custom crypto. The choices are conservative and aimed at long-term resilience rather than raw performance.
Primitive
Role
Parameters
Argon2id
Password-based key derivation. Stretches user and master passphrases before any DNS lookup.
Authenticated encryption of every TXT record (master passphrase, IP, certificate parameters, ECH config).
256-bit key · 96-bit nonce · 128-bit tag
ECDSA P-256
TLS certificate signing. The private key is shipped in the DNS record; both client and server sign with deterministic ECDSA (RFC 6979) so the resulting certificate is byte-for-byte identical on both ends.
NIST P-256 (secp256r1) · SHA-256 · RFC 6979
HPKE X25519
Encrypted Client Hello. Hides the SNI field from observers during the TLS handshake.
X25519 + HKDF-SHA256 + AES-128-GCM (RFC 9180)
DNSSEC (recommended)
Authenticates DNS responses end-to-end. Prevents on-path tampering of TXT records.
Provider-side configuration
DoH / DoT (recommended)
Encrypts DNS queries between the client and its resolver. Hides the lookup itself from local observers.
Resolver-side configuration
The full byte-level format of each record, the exact derivation steps, and the test vectors live in the protocol specification.
The server's life is a rotation cycle. Generate a new master passphrase, generate a fresh ECDSA P-256 key pair and the matching certificate, encrypt all the records (including the private key), publish them. Then wait until the next rotation (90 days by default) — or until a revocation forces an earlier one. There is no listener, no resident process: trantor is a one-shot CLI.
One pass per cycle. No daemon, no open port, no exposed surface.
Client side — silent refresh
Each Terminus instance polls its managed domains on a regular cadence (the DNS records carry a TTL, recommended 300 seconds, and Terminus refreshes when that TTL expires). The refresh is a compare-and-update: Terminus pulls the records, rebuilds the certificate in memory, and compares it byte-for-byte with the certificate currently sitting in the OS trust store.
If the two are identical (no rotation has happened on the server), Terminus does nothing — no write to the trust store, no churn.
If they differ (the server has rotated, or the master passphrase has been revoked), Terminus replaces the trust-store entry with the freshly built certificate. In-flight HTTPS connections keep using the old one until they close on their own.
From the user's point of view, the rotation is invisible: the browser keeps talking to the same hostname, the trust store quietly catches up, and connections that were already open finish normally.
Most of this page describes the default mode — full stealth with a strong user passphrase. Trantor also supports two relaxed modes for cases where stealth is not the goal, or where a domain needs to serve both Trantor users and the open internet.
Standard mode
The default. Each user holds a strong passphrase; DNS record names are derived from it through Argon2id. Without the passphrase, an observer cannot enumerate, locate, or fingerprint a Trantor-managed hostname. This is the mode assumed everywhere else on this page.
Empty passphrase
The server is configured with an empty passphrase (""). Resolution still works — the DNS record name is just derived from Argon2id("", hostname). The trade-off is explicit: anyone who knows the hostname can confirm the server uses Trantor by computing that hash, so stealth is gone. Useful for public services that want a CA-free TLS certificate, parallel community networks, or internal infrastructure where stealth doesn't matter.
Hybrid deployment
A single hostname can publish standard A/AAAA/CNAME records and Trantor TXT records under hashed names. Visitors without Terminus reach the public-facing server normally; visitors running Terminus get redirected to the Trantor-protected one. Both targets can point to the same machine on different ports, or to entirely different servers — the choice is yours.
This page is the protocol from a thousand feet up. The exact byte-level encoding of records, the full derivation steps, the threat model with assumptions and non-goals, and the test vectors are all in the technical specification.