Back to guides
Runbook

Verified DDR, End to End.

Discovery is easy to demonstrate and hard to run strictly: the verified mode ties the whole mechanism to one unusual requirement, a TLS certificate that covers an IP address. This is the full account of running it in production on this resolver - the standards, the certificate engineering, a first design we built and then replaced, and the commands to check every claim yourself.

Your device knows one thing: 194.180.189.33 One plain SVCB query _DNS.RESOLVER.ARPA Three designations come back dnsdoh.art · DoH h2/h3 · DoT · DoQ TLS handshake with dnsdoh.art the certificate decides everything Verified. Encrypted from here on port 53 is no longer used TLS CERTIFICATE · SUBJECT ALT NAMES DNS: dnsdoh.art IP: 194.180.189.33 must cover the designated name AND the IP the device started from The reply travels in plain DNS. The certificate is what makes it safe to believe.

Verified DDR in one picture: a plain-text answer, held to a cryptographic standard.

If you want the concept from the beginning - what DDR and DNR are and how they differ - start with how devices discover encrypted DNS. This guide is the operator's side of the same story.

The standards, in one minute

Three documents define the machinery:

  • RFC 9462 - Discovery of Designated Resolvers. Defines the special name _dns.resolver.arpa, the query a client sends, and the two trust levels: opportunistic and verified.
  • RFC 9460 - the SVCB record type the answer is written in: a priority, a target name, and parameters such as alpn, port and dohpath.
  • RFC 9463 - DNR, the sibling mechanism where DHCP or an IPv6 router advertisement carries the designation instead. Same certificate rules, different messenger.

The part that gives this guide its subject is RFC 9462's verified mode. A client in verified mode requires the designated server's certificate to cover the IP address it originally bootstrapped from, not just the designated name. Windows 11 enforces this, and iOS 16 and macOS 13 perform the same discovery. That single sentence in the standard decides most of the engineering below.

The strictness exists for a reason. The discovery query travels in plain DNS, so on a network you do not control - a compromised home router, a public Wi-Fi gateway - anything on the path can answer it and designate a server of its own choosing. That is a man-in-the-middle (MITM) attack on the bootstrap itself: hijack the one unencrypted question, and every "encrypted" lookup afterwards goes to the attacker. The IP requirement closes it. An impostor would need a publicly trusted certificate for an address it does not own, the CA will not issue one, and the handshake fails. Verification does not make the plain-text answer trustworthy; it makes lying in it useless.

The live answer

This is not a lab example. Ask this resolver right now:

$ dig @194.180.189.33 _dns.resolver.arpa SVCB +short
1 dnsdoh.art. alpn="h2,h3" port=443 dohpath="/dns-query{?dns}"
1 dnsdoh.art. alpn="dot" port=853
1 dnsdoh.art. alpn="doq" port=853

Three designations, one name. DoH over HTTP/2 or HTTP/3 on 443 with the query-URL template, DoT on 853, DoQ on 853. Every line points at dnsdoh.art - the same address printed everywhere on this site - and every line is intended to survive the strict check. Getting all three lines to that state is the story of the next four sections.

The certificate problem: an IP address in the SAN

A certificate that covers an IP address is an ordinary X.509 certificate with an IP Address entry in its Subject Alternative Names. Browsers have understood them for decades. Getting one issued for free, with automation, is another matter, and in 2026 the practical landscape is narrow:

  • Let's Encrypt is currently the only ACME CA that issues publicly trusted IP-address certificates without payment. Support became generally available in January 2026.
  • Only in the short-lived profile. IP certificates are issued exclusively with about six and a half days of validity (160 hours). There is no 90-day option for an IP.
  • No DNS-01 for IPs. An IP identifier can only be validated over http-01 or tls-alpn-01 - the CA connects to the address itself. This has a sharp consequence: wildcard names require dns-01, so a wildcard certificate can never carry an IP. If your stack lives on a wildcard, "just add the IP" is impossible; the certificate strategy has to change.

The issuance itself is unremarkable once those constraints are accepted. With certbot 5.6+:

$ certbot certonly --webroot -w /var/www/acme \
    -d dnsdoh.art -d www.dnsdoh.art \
    --ip-address 194.180.189.33 \
    --required-profile shortlived --reuse-key

Two flags matter beyond the obvious. --required-profile shortlived makes the profile explicit rather than an accident of what the CA offers, and --reuse-key keeps the public key identical across renewals - which is what allows DNS-pinned keys to survive a certificate that changes every week. More on that below.

Round one: a separate discovery name

Our first design kept the risk away from the main stack. The production certificate at the time was a 90-day wildcard - which, per the rules above, could never carry the IP. Rather than rebuild the whole stack's certificate strategy to run an experiment, we added one dedicated vhost, ddr.dnsdoh.art, serving only /dns-query, with its own short-lived certificate covering exactly the pair the standard demands: that name plus IP:194.180.189.33. The DDR answer designated the discovery name for DoH, and everything else stayed untouched.

It worked. A Windows 11 machine pointed at the bare IP discovered the endpoint, verified the certificate against the address it started from, and filled in the DoH template on its own. As a proof that strict clients accept a correctly built designation, the experiment did its job.

Running it also exposed the design's limits:

  • Only DoH was verified. DoT and DoQ terminate on the resolver itself under the main certificate, which had no IP SAN. Our resolver software deliberately refuses to advertise a DoT designation unless the certificate it serves carries an IP address, precisely because a strict client would fail the handshake. One transport verified, two left behind.
  • Two public names for one service. Users saw dnsdoh.art everywhere on the site and a second name inside their OS settings after discovery. Technically harmless, humanly confusing.
  • Two certificate lineages to operate. Separate renewals, separate monitoring, separate DANE records - permanent operational surface for what was meant to be a bounded experiment.

The lesson was not that the design was wrong - isolation was the right way to test - but that the test had answered its question. Short-lived issuance and renewal had run cleanly for days. The remaining risk was no longer the mechanism; it was keeping two arrangements alive when one would do.

Round two: one certificate for everything

The second design inverted the first. Instead of quarantining the IP SAN on a side name, the whole stack moved to a single short-lived certificate carrying the site names and the resolver address - served identically on 443 for the website and DoH, and on 853 for DoT and DoQ. With the certificate able to survive the strict check on every transport, DDR could designate dnsdoh.art directly, and the discovery alias was dropped from the answer.

What that bought, concretely:

  • All three transports verified. The moment the designation target matched the server name and the certificate carried the IP, the DoT designation appeared alongside DoH and DoQ - the software's gate opened because the check it protects now passes.
  • One name, everywhere. What discovery writes into the OS is the same dnsdoh.art/dns-query a user would copy from the setup page.
  • One renewal pipeline, one set of pins, one thing to monitor.

The trade is equally concrete: the entire stack now lives on a certificate that expires in six and a half days, forever. That is not a decision to take casually, and it moves the engineering problem from issuance to operations - the subject of the next section.

The transition itself was done as one scripted cutover with a snapshot and a tested revert path, and the old discovery name was kept answering through a grace window for any client that had latched onto it before being retired. The change is also recorded in the news announcement from the day it happened.

ONE 160-HOUR CERTIFICATE, AS OPERATED normal service alert window · only if renewal failed renewal fires here (ARI) ~2 days of margin left expiry day 0 1 2 3 4 5 6 160 h The key pair does not rotate (reuse-key), only the certificate around it. So the DANE TLSA pins published in the DNSSEC-signed zone stay valid across every weekly renewal.

A week-long certificate is only stressful if renewal is an event. Automated, it is a rhythm.

Living with 160-hour certificates

Everything that follows from the short lifetime reduces to three practices:

  • Renewal is driven by the CA's own schedule. ACME Renewal Information (ARI) lets the CA tell the client the ideal replacement window, and certbot follows it. In practice the certificate is replaced with roughly two days of validity to spare, without a hand-tuned cron guess.
  • The key never changes. With --reuse-key, every renewal wraps the same key pair in a fresh certificate. The DANE TLSA records pinning that key in the DNSSEC-signed zone stay correct without touching DNS week after week.
  • Monitoring assumes failure. A watchdog checks the renewal state and remaining validity every few hours and alarms long before expiry - at a threshold the ARI schedule should never let the certificate reach. Silence means healthy; an alert means there are still about two days to fix issuance.

The failure mode is worth stating honestly. If renewal broke and the certificate expired, strict clients would fail verification and fall back to whatever they were configured with - resolution itself does not go dark, discovery just stops being verified until issuance is repaired. That containment, plus the margin in the chart above, is what makes a one-week certificate an acceptable foundation rather than a gamble.

Verify every claim yourself

Nothing above needs to be taken on trust. Three commands reproduce the whole chain. The discovery answer:

$ dig @194.180.189.33 _dns.resolver.arpa SVCB +short

The certificate, with the IP in its SAN list - the line verified DDR stands on:

$ echo | openssl s_client -connect dnsdoh.art:443 2>/dev/null \
    | openssl x509 -noout -ext subjectAltName
X509v3 Subject Alternative Name: critical
    DNS:dnsdoh.art, ..., IP Address:194.180.189.33

And the designated endpoint answering a real query over HTTP/3, the way a discovering client would use it (curl 8.6+ built with HTTP/3 support):

$ curl --http3-only -s -o /dev/null -w '%{http_code} http/%{http_version}\n' \
    -H 'accept: application/dns-message' \
    'https://dnsdoh.art/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE'
200 http/3

On a Windows 11 machine the end-to-end test is even simpler: set the DNS server to 194.180.189.33, toggle the interface off and on, and watch the DoH template appear by itself under the encrypted DNS settings. Which transport the client then prefers is its own choice - the transports compared covers what each is good at.

Or skip the discovery and choose directly

Discovery upgrades whatever resolver a network hands you. Choosing your own encrypted resolver decides the other half: who answers.

Set up encrypted DNS

Related: DDR and DNR explained from the start, DNS record types for SVCB and TLSA, and what DNSSEC signs in the zone the pins live in.