DNS Records
Directory uses two standard DNS record types. The drs CLI automates this for Cloudflare, but you can create these records manually on any provider.
Service Discovery — SRV
Locates the DRS for a domain. Analogous to MX records for email.
_drs._tcp.yourcompany.com SRV 10 5 443 yourcompany.com| Field | Type | Description |
|---|---|---|
priority | integer | Lower values preferred (same as MX) |
weight | integer | Relative weight for same-priority records |
port | integer | Always 443 (HTTPS only) |
target | string | Hostname of the DRS |
Client behavior:
- Query
_drs._tcp.{domain}for SRV records. - Select target using standard SRV priority/weight algorithm (RFC 2782).
- Open an HTTPS connection to the selected target.
Public Key Distribution — TXT
Publishes the Ed25519 public key(s) for routing contract verification. This is DKIM for value routing.
_drskey.yourcompany.com TXT "v=drs1; k=ed25519; p=BASE64PUBLICKEY"| Field | Type | Description |
|---|---|---|
v | string | Protocol version. Always drs1. |
k | string | Key type. Always ed25519. |
p | string | Base64-encoded Ed25519 public key (raw 32 bytes). |
Parsing rules:
- Fields are semicolon-delimited
key=valuepairs. - Whitespace around delimiters is ignored.
vMUST equaldrs1,kMUST equaled25519.pMUST be valid base64 decoding to exactly 32 bytes.- Unknown fields MUST be ignored (forward compatibility).
Multiple keys for rotation. Operators MAY publish more than one _drskey TXT record. Clients MUST attempt signature verification against every valid record and consider the signature valid if any one succeeds. This is how key rotation happens without breaking senders in flight: publish the new key, wait for DNS TTLs to expire, flip the signing key, then remove the old record.
Client behavior:
- Fetch all
_drskeyrecords before verifying any routing contract. - Skip records that fail to parse; do not fail the whole lookup.
- Cache for the record’s DNS TTL only.
- On signature verification failure, re-fetch the records once and retry — this handles the moment an operator rotates.
DNSSEC
Directory’s trust model starts at DNS. The SRV record tells senders where to connect. The TXT record tells them which public keys to trust. If an attacker poisons either record, they control the routing.
DNSSEC is strongly recommended for any domain running a Directory node.
Without DNSSEC, a DNS cache poisoning attack can substitute a fake public key in _drskey, stand up a node at a fake SRV target, and sign contracts with the attacker’s key. The client verifies the signature — it passes — and sends to the wrong destination. The Ed25519 signature protects against tampering after discovery. DNSSEC protects discovery itself.
Enabling DNSSEC
Most DNS providers support DNSSEC. It requires two steps:
- Enable DNSSEC signing in your DNS provider’s dashboard.
- Add the DS record to your domain registrar.
| Provider | DNSSEC Support |
|---|---|
| Cloudflare | One-click enable in DNS settings |
| AWS Route 53 | Supported via KMS signing keys |
| Google Cloud DNS | Supported via DNSSEC settings |
| GoDaddy | Supported for most TLDs |
Verify with:
dig +dnssec _drskey.yourcompany.com TXTA valid DNSSEC response includes RRSIG records alongside the answer.
Client behavior
Clients SHOULD validate DNSSEC when available. When DNSSEC validation is not possible (e.g., in browser environments), clients MUST still verify the Ed25519 contract signature and SHOULD warn users if the domain lacks DNSSEC.
Creating Records by Provider
Any provider (manual)
First, generate your Ed25519 keypair:
pnpm tsx scripts/gen-keypair.tsThen create two DNS records in your provider’s dashboard:
Record 1 — SRV
| Setting | Value |
|---|---|
| Type | SRV |
| Name | _drs._tcp |
| Priority | 10 |
| Weight | 5 |
| Port | 443 |
| Target | yourcompany.com |
| TTL | 3600 (or auto) |
Record 2 — TXT
| Setting | Value |
|---|---|
| Type | TXT |
| Name | _drskey |
| Value | v=drs1; k=ed25519; p=YOUR_BASE64_PUBLIC_KEY |
| TTL | 3600 (or auto) |
Cloudflare
The drs CLI handles this automatically:
drs init --domain yourcompany.com --cf-token <token>AWS Route 53
# SRV recordaws route53 change-resource-record-sets --hosted-zone-id <zone-id> --change-batch '{ "Changes": [{ "Action": "CREATE", "ResourceRecordSet": { "Name": "_drs._tcp.yourcompany.com", "Type": "SRV", "TTL": 3600, "ResourceRecords": [{"Value": "10 5 443 yourcompany.com."}] } }]}'
# TXT recordaws route53 change-resource-record-sets --hosted-zone-id <zone-id> --change-batch '{ "Changes": [{ "Action": "CREATE", "ResourceRecordSet": { "Name": "_drskey.yourcompany.com", "Type": "TXT", "TTL": 3600, "ResourceRecords": [{"Value": "\"v=drs1; k=ed25519; p=YOUR_BASE64_PUBLIC_KEY\""}] } }]}'Other registrars
Most registrar DNS dashboards support SRV and TXT records. Look for “Advanced DNS” or “DNS Management” and create the two records using the values above.
Verifying your records
dig _drs._tcp.yourcompany.com SRVdig _drskey.yourcompany.com TXT
drs check-dns yourcompany.comHosting the DRS
The DNS records point senders to your DRS. The DRS itself can run anywhere that serves HTTPS:
| Platform | How |
|---|---|
| Cloudflare Workers | wrangler deploy — the reference implementation |
| Any Node.js host | Run the Hono app with @hono/node-server |
| Docker / VPS | Wrap the Node.js server in a container behind nginx/caddy with TLS |
| Vercel / Fly.io / Railway | Deploy the Hono app as a standard Node.js HTTP server |
The only requirement is that the host serves HTTPS on port 443 at the domain specified in your SRV record’s target. The DRS is a stateless HTTPS API — it works anywhere you can run a web server.
For non-Cloudflare deployments, you bring your own storage backend. The DRS defines a KVStore interface:
interface KVStore { get(key: string): Promise<string | null>; put(key: string, value: string): Promise<void>; delete?(key: string): Promise<void>; list?(): Promise<{ keys: { name: string }[] }>;}Cloudflare KVNamespace satisfies this natively. For other platforms, implement get and put against Redis, Postgres, SQLite, DynamoDB — whatever you have. A MemoryKV adapter ships with the reference implementation for local development and testing.