Server (trantor)
Overview #
trantor is the reference server-side implementation, written in Go. It is a one-shot CLI: it does not stay resident, it does not listen on any port, and it doesn't terminate any TLS connections itself. Its only job is to publish (and refresh) encrypted DNS records that describe how clients can reach the actual web server.
Once the records are published, your existing web server (nginx, Apache, Caddy, anything that speaks HTTPS) takes over. trantor hands it a forged TLS certificate and bows out.
Architecture #
The server has four cooperating modules:
- Crypto — Argon2id key derivation, AES-256-GCM record encryption, ECDSA P-256 certificate forging, HPKE X25519 ECH key generation.
- DNS — TXT record publish/update via the libdns library, a Go interface that abstracts ~20 DNS providers behind a common API.
- State — local configuration in
/etc/trantor/: master passphrase, list of user passphrases, ECH key material, scheduled rotation timestamps. - CLI — the user-facing surface:
init,passphrase add/remove/list,publish,renew,status.
Commands #
init
Initialize a new domain. Generates the master passphrase, picks ECH key material, writes the configuration to /etc/trantor/<domain>.json.
sudo trantor init \
--domain foo.bar.com \
--provider cloudflare \
--ech true
passphrase add | remove | list
Manage user passphrases. Each passphrase is named for traceability (e.g. "alice", "team-alpha") and is generated server-side — never typed by the operator.
sudo trantor passphrase add --domain foo.bar.com --name "alice"
sudo trantor passphrase list --domain foo.bar.com
sudo trantor passphrase remove --domain foo.bar.com --name "alice"
publish
Push the current state to DNS. Idempotent — running it twice doesn't change anything if nothing has changed locally.
sudo trantor publish --domain foo.bar.com
renew
Force-rotate the master passphrase, re-encrypt all user records, and republish. Normally automatic every 90 days; useful manually after suspected compromise.
sudo trantor renew --domain foo.bar.com
status
Print the current state for a domain: number of user passphrases, last publish, next scheduled rotation, ECH key fingerprint.
Supported DNS providers #
trantor uses libdns for DNS publishing — a Go ecosystem of small, focused provider packages (around 20 today and growing), all implementing the same record-management interface. Supported providers include:
- Cloudflare, Route53 (AWS), Google Cloud DNS, Azure DNS
- Gandi, OVH, Hetzner, Namecheap
- DigitalOcean, Linode (Akamai), Vultr
- plus a handful of regional and self-hosted backends (PowerDNS, ALIDNS, Mailcow, …)
If your provider isn't supported, the recommended path is to contribute a new libdns provider package upstream — they are small, single-purpose, and the libdns project actively welcomes them.
Lifecycle #
Two events drive the server's state changes:
- Scheduled rotation (every 90 days) — the master passphrase is regenerated, all user records are re-encrypted under the new master, and DNS is updated. Clients pick up the new master at their next refresh, transparently.
- Revocation — same as a rotation, but the revoked user's record is also deleted from DNS. Existing users are unaffected; the revoked user loses access immediately.
You can run publish automatically from cron or a systemd timer, but the server already schedules its own rotation — there is nothing extra to wire.
Deployment modes #
The server supports three deployment modes (covered in detail on the how-it-works page). The mode is chosen at init time:
- Standard — the default. Each user gets a passphrase generated by
trantor passphrase add. Full stealth. - Empty passphrase — pass
--passphrase ""atinit. The DNS record is published underArgon2id("", hostname), and any client knowing the hostname can resolve it. Useful for public services that want CA-free TLS, parallel community networks, or non-stealth internal services. - Hybrid — the same hostname carries both a regular
A/AAAA/CNAMErecord (toward a public-facing server) and Trantor TXT records (toward the protected one). No special server flag — just keep the standard records in your DNS zone alongside the onestrantor publishwrites.
Configuration & deploy hook #
trantor init writes its state and configuration to /etc/trantor/<domain>.conf. The file holds the master passphrase, the user passphrase records, the ECH key material, and the renewal schedule — all material an attacker would need to impersonate the server. The file must be mode 600 (owner read/write only) and is rejected at startup otherwise.
Deploy hook
After every successful renewal, trantor can run a deploy_hook to reload the web server, push the new certificate to a load balancer, or trigger any other side effect. The hook is an array of commands executed sequentially; if any command fails, the chain stops and the failure is logged.
{
"deploy_hook": [
{ "command": "systemctl reload nginx", "timeout": "30s" },
{ "command": "apachectl graceful" }
]
}
Each entry takes:
command(string, required) — the shell command line to run.timeout(Go duration, optional) — e.g."30s","2m","500ms". Default"0"means no timeout.
Commands run under the same UID as trantor itself (typically root, since the daemon needs DNS-provider credentials and certificate filesystem access). Both stdout and stderr are captured and written to the trantor log.
Source code #
The server lives in the cmd/trantor directory of the Trantor repository. Issues and pull requests are welcome.