Skip to content

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
FieldTypeDescription
priorityintegerLower values preferred (same as MX)
weightintegerRelative weight for same-priority records
portintegerAlways 443 (HTTPS only)
targetstringHostname of the DRS

Client behavior:

  1. Query _drs._tcp.{domain} for SRV records.
  2. Select target using standard SRV priority/weight algorithm (RFC 2782).
  3. 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"
FieldTypeDescription
vstringProtocol version. Always drs1.
kstringKey type. Always ed25519.
pstringBase64-encoded Ed25519 public key (raw 32 bytes).

Parsing rules:

  • Fields are semicolon-delimited key=value pairs.
  • Whitespace around delimiters is ignored.
  • v MUST equal drs1, k MUST equal ed25519.
  • p MUST 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 _drskey records 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:

  1. Enable DNSSEC signing in your DNS provider’s dashboard.
  2. Add the DS record to your domain registrar.
ProviderDNSSEC Support
CloudflareOne-click enable in DNS settings
AWS Route 53Supported via KMS signing keys
Google Cloud DNSSupported via DNSSEC settings
GoDaddySupported for most TLDs

Verify with:

Terminal window
dig +dnssec _drskey.yourcompany.com TXT

A 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:

Terminal window
pnpm tsx scripts/gen-keypair.ts

Then create two DNS records in your provider’s dashboard:

Record 1 — SRV

SettingValue
TypeSRV
Name_drs._tcp
Priority10
Weight5
Port443
Targetyourcompany.com
TTL3600 (or auto)

Record 2 — TXT

SettingValue
TypeTXT
Name_drskey
Valuev=drs1; k=ed25519; p=YOUR_BASE64_PUBLIC_KEY
TTL3600 (or auto)

Cloudflare

The drs CLI handles this automatically:

Terminal window
drs init --domain yourcompany.com --cf-token <token>

AWS Route 53

Terminal window
# SRV record
aws 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 record
aws 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

Terminal window
dig _drs._tcp.yourcompany.com SRV
dig _drskey.yourcompany.com TXT
drs check-dns yourcompany.com

Hosting the DRS

The DNS records point senders to your DRS. The DRS itself can run anywhere that serves HTTPS:

PlatformHow
Cloudflare Workerswrangler deploy — the reference implementation
Any Node.js hostRun the Hono app with @hono/node-server
Docker / VPSWrap the Node.js server in a container behind nginx/caddy with TLS
Vercel / Fly.io / RailwayDeploy 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.