DoH (DNS over HTTPS)
DNS over HTTPS (DoH), defined in RFC 8484, carries each DNS query and answer inside an HTTPS request to a resolver URL instead of a plaintext port-53 packet, encrypting and authenticating the stub-to-recursive hop. It hides lookups from on-path devices; unlike DNSSEC it does not sign them.
Also known as Secure DNS.
Full Explanation
DNS over HTTPS (DoH) carries each DNS query and its answer inside an ordinary HTTPS request. RFC 8484 defines the protocol. Each HTTP exchange carries one query-response pair. The request goes to a resolver URL, such as https://cloudflare-dns.com/dns-query. This replaces the plaintext UDP packet DNS normally sends on port 53. The HTTPS connection is sealed by TLS, which encrypts the query and authenticates the resolver.
DoH is not DoT (DNS over TLS). DoT listens on a dedicated port, 853. DoH is indistinguishable from other traffic on port 443, and may even share a connection with it. DoH is not DNSSEC either. DoH encrypts the channel, DNSSEC signs the data. RFC 8484 calls them "independent and fully compatible protocols, each solving different problems" (Section 9). DoH is also not end-to-end privacy. RFC 8484 covers only the hop from a stub resolver to a recursive resolver (Section 1). The resolver you choose still sees every query you make. Its own queries to authoritative servers normally leave unencrypted. DoH changes who can watch your lookups. It does not remove the need to trust anyone.
How it works
- Configuration. The client holds a URI Template, which describes how to build the request URL. RFC 8484 itself leaves configuration, discovery and updating of that template out of band. It does allow automatic sources such as DHCP (Section 3). Discovery is no longer purely manual. RFC 9462 (Discovery of Designated Resolvers) helps here: it lets a client that knows only a resolver's IP address query SVCB records at _dns.resolver.arpa to learn the encrypted-DNS endpoint that resolver designates. RFC 9463 carries the same details in DHCP and IPv6 Router Advertisement options.
- Request. Each HTTP request carries one DNS message. Clients may use either GET or POST; servers must implement both (Section 4.1). GET carries the message base64url-encoded, without padding characters, in a variable named "dns"; POST sends the raw binary message as the body (Section 6). Either way the media type is application/dns-message.
- Response. The response is a single DNS message. It uses the classic on-the-wire format of RFC 1035, capped here at 65535 bytes. This is deliberately not DoT's framing, which prefixes two length bytes (Section 6). HTTP status and DNS status are separate layers. Any valid DNS response, including a failure code such as SERVFAIL or NXDOMAIN, comes back with a successful 2xx status. A non-2xx status means the HTTP request itself failed and carries no answer at all (Section 4.2.1).
- Transport. The https scheme is mandatory (Section 5). HTTP/2 is "the minimum RECOMMENDED version of HTTP for use with DoH", because matching plain UDP DNS needs reordering, parallelism, priority and header compression (Section 5.2). Many queries then share one connection. Clients on HTTP/3 over QUIC additionally avoid TCP head-of-line blocking. Because HTTP already correlates request with response, the DNS ID is redundant. Clients should send DNS ID 0 in every request: a varying ID makes semantically identical queries cache separately (Section 4.1).
- Bootstrap. The obvious circularity applies. A client cannot use its DoH server to resolve that server's own hostname. So the address must come from configuration, an IP-based URI, or plain DNS. The same section flags a subtler deadlock. If the TLS handshake triggers an OCSP or AIA fetch that itself needs DNS, resolution stalls (Section 10).
Why it matters for a CDN
- Edge selection gets harder. DoH moves lookups from the nearby ISP resolver to a handful of large resolvers. RFC 7871 calls these Centralized Resolvers: intermediate nameservers serving a topologically diverse address space. A CDN's authoritative nameserver never sees the DoH client's address, only the recursive resolver's. That is because the HTTPS connection terminates there (RFC 7871, Section 1). So geo-DNS can no longer assume resolver location approximates user location. It depends on EDNS Client Subnet, which the resolver must choose to send, or on the resolver being anycast close to the user anyway.
- HTTP caching lands in the DNS path. A DoH exchange "can pass through a hierarchy of caches", and RFC 8484 names content delivery networks among the upstream caches that will not understand DoH semantics (Section 5.1). Three rules follow from the same section. The freshness lifetime of a DoH response must be no greater than the smallest TTL in the Answer section, and equal to it is recommended. For a negative answer carrying an SOA in the Authority section it must not exceed that SOA's MINIMUM field. Clients must also subtract the Age header from the TTL when reading a cached response. Miss any of these rules, and a cache serves records that have already expired.
- Cacheability depends on the method. GET is "friendlier to many HTTP cache implementations" (Section 4.1). Responses to POST are not cacheable unless specific response header fields are sent, which RFC 8484 notes is not widely implemented and not advised for DoH (Section 5.1). Google Public DNS puts it plainly: POST "reduces the cacheability of responses and can increase DNS latency, so it is not generally recommended".
- The first hop becomes tamper-resistant. Encryption plus server authentication mitigates passive surveillance. It also mitigates active attacks that try to divert DNS traffic to rogue servers (Section 8.1). This is the hijacking that captive portals and some ISPs perform on plaintext lookups.
- It is just HTTP, so a CDN can serve it. RFC 8484 deliberately "aligns itself with HTTP features such as caching, redirection, proxying, authentication, and compression" (Section 1). So existing TLS termination, anycast and edge servers host a DoH endpoint unchanged.
- It gives web apps a DNS API. The second use case in RFC 8484 is letting web applications reach DNS through existing browser APIs consistently with CORS (Section 1). Google notes this exposes every DNS record type to a web app, "avoiding the limitations of existing browser and OS DNS APIs, which generally support only host-to-address lookups". DoT cannot offer this.
What CDNs do
- Cloudflare runs a public DoH resolver at https://cloudflare-dns.com/dns-query. It supports POST and GET for DNS wire format, and GET for JSON, with no authentication required. Note for geo-routing: 1.1.1.1 does not send EDNS Client Subnet, because it "is a privacy-focused resolver and does not include client IP information in its queries to authoritative servers". The one documented exception is Akamai's whoami.ds.akahelp.net debug domain (Cloudflare 1.1.1.1 FAQ). Firefox has shipped Cloudflare as its default DoH resolver for US users since February 2020, with NextDNS as the alternative.
- Google Public DNS exposes two endpoints. https://dns.google/dns-query serves RFC 8484 wire format over GET and POST, and https://dns.google/resolve serves a JSON API over GET only. Unlike Cloudflare it does send ECS, and it auto-detects ECS support by nameserver IP address, so a CDN zone's ECS behaviour directly changes the answers Google returns.
- Quad9 serves its recommended filtering resolver over DoH at https://dns.quad9.net/dns-query. That resolver blocks malware and validates DNSSEC. ECS is not on that endpoint: it is a separate service at https://dns11.quad9.net/dns-query. You opt in by choosing the endpoint.
- AWS Route 53 Resolver has accepted DoH on inbound and outbound Resolver endpoints since December 2023, with a DoH-FIPS variant for inbound endpoints. Hybrid networks can then encrypt DNS between VPCs and on-premises. Each endpoint can allow port-53 DNS, DoH, or both, or enforce DoH only; port-53 DNS remains the default.
Watch out for
- One hop only. The recursive resolver still sees every query in the clear. Its traffic onward to authoritative servers is normally plaintext (Section 1). Picking DoH picks whom you trust.
- Encryption is not integrity. The HTTPS connection "does not provide the response integrity of DNS data provided by DNSSEC" (Section 9). Without validation you are simply trusting the resolver's answers.
- Network filtering stops working. "Filtering or inspection systems that rely on unsecured transport of DNS will not function in a DNS over HTTPS environment" (Section 10), by design. Chrome's "Secure DNS" is on by default in automatic mode and falls back to unencrypted lookups when that fails. It is unavailable, though, when the device is managed or parental controls are on (Chrome Help). That policy carve-out, not port blocking, is the intended control point.
- ECS is optional and deliberately coarse. RFC 7871 recommends the feature be turned off by default in nameserver software, and enabled only where it clearly benefits clients. It also asks resolvers to truncate IPv4 addresses to 24 bits and IPv6 to 56 bits (RFC 7871, Section 11.1). A CDN gets a subnet at best, and from resolvers like 1.1.1.1 nothing at all.
- New correlation surface. "HTTPS presents new considerations for correlation, such as explicit HTTP cookies and implicit fingerprinting of the unique set and ordering of HTTP request header fields" (Section 8.2). Plain UDP DNS carries no client identifiers at all.
- Centralization. "An increased proportion of the global DNS resolution traffic being served by only a few entities means that the privacy considerations for users are highly dependent on the privacy policies and practices of those entities" (RFC 9076, Section 6.1.1).
- Whoever owns the cache owns the view. "An adversary that can control the cache used by the client can affect that client's view of the DNS" (Section 9). This puts every HTTP cache on the path, a CDN included, inside the trust boundary.
- No ordering guarantees. HTTP is stateless, so DoH provides no stateful ordering between requests and cannot transport protocols that need strict ordering. Transport-specific DNS extensions such as edns-tcp-keepalive do not apply (Section 10).
Best practice
- Cap freshness explicitly. Set Cache-Control max-age equal to the smallest TTL in the Answer section, never above it. Keep negative answers within the SOA MINIMUM. Subtract Age from the TTL when consuming a cached response (Section 5.1).
- Prefer GET and send DNS ID 0 in every request, so semantically identical queries share one cache entry (Section 4.1). Keep POST for privacy-sensitive paths where suppressing caching is the point.
- Leave DNSSEC validation on. "The use of one does not diminish the need nor the usefulness of the other" (Section 9).
- For geo-routing, enable ECS deliberately and on every authoritative nameserver for the zone. Google warns that one nameserver without ECS becomes the source of most cached data, because its global-scope answers get reused for all client subnets. Verify that answers really change with client subnet. Keep edge selection tolerant for the resolvers that send no ECS at all.
- Design out both bootstrap deadlocks. Pin the resolver address in configuration, or use an IP-based URI with a matching certificate. Never let the TLS handshake depend on a DNS-resolved OCSP or AIA fetch. Staple the certificate status instead (Section 10).
- Keep the HTTP surface minimal. RFC 8484 says HTTP cookies "SHOULD NOT be accepted by DoH clients unless they are explicitly required by a use case" (Section 8.2). Google advises sending only Host, Content-Type and, if needed, Accept.
- If you must filter, run a filtering DoH resolver, whether Quad9's blocking endpoints or your own, and set client policy. Intercepting plaintext port-53 traffic achieves nothing once clients use DoH (Section 10).
Examples
# Query DoH with curl (Cloudflare)
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=example.com&type=A' | \
python3 -m json.tool
# Returns JSON with Answer section
# Query DoH with curl (Google, wire format)
curl -s -H 'content-type: application/dns-message' \
'https://dns.google/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE' | \
xxd
# Enable DoH on Linux with systemd-resolved
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com
DNSOverTLS=no
# Note: systemd-resolved supports DoT natively, DoH via stub
# Firefox DoH settings
# about:config
# network.trr.mode = 2 (DoH with fallback)
# network.trr.mode = 3 (DoH only, no fallback)
# network.trr.uri = https://cloudflare-dns.com/dns-query
# Test DoH resolver response time
curl -o /dev/null -s -w '%{time_total}\n' \
'https://cloudflare-dns.com/dns-query?name=example.com&type=A' \
-H 'accept: application/dns-json'
# 0.025 (25ms including TLS handshake)
Frequently Asked Questions
DNS over HTTPS (DoH), defined in RFC 8484, carries each DNS query and answer inside an HTTPS request to a resolver URL instead of a plaintext port-53 packet, encrypting and authenticating the stub-to-recursive hop. It hides lookups from on-path devices; unlike DNSSEC it does not sign them.
# Query DoH with curl (Cloudflare)
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=example.com&type=A' | \
python3 -m json.tool
# Returns JSON with Answer section
# Query DoH with curl (Google, wire format)
curl -s -H 'content-type: application/dns-message' \
'https://dns.google/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE' | \
xxd
# Enable DoH on Linux with systemd-resolved
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com
DNSOverTLS=no
# Note: systemd-resolved supports DoT natively, DoH via stub
# Firefox DoH settings
# about:config
# network.trr.mode = 2 (DoH with fallback)
# network.trr.mode = 3 (DoH only, no fallback)
# network.trr.uri = https://cloudflare-dns.com/dns-query
# Test DoH resolver response time
curl -o /dev/null -s -w '%{time_total}\n' \
'https://cloudflare-dns.com/dns-query?name=example.com&type=A' \
-H 'accept: application/dns-json'
# 0.025 (25ms including TLS handshake)
Yes. DoH (DNS over HTTPS) is also known as Secure DNS. DNS over HTTPS (DoH), defined in RFC 8484, carries each DNS query and answer inside an HTTPS request to a resolver URL instead of a plaintext port-53 packet, encrypting and authenticating the stub-to-recursive hop. It hides lookups from on-path devices; unlike DNSSEC it does not sign them.
Related CDN concepts include:
- DNS (Domain Name System) (DNS) — The distributed, hierarchical naming system that resolves names like example.com to addresses. A query-response lookup …
- A Record — An A record is the DNS record type that maps a hostname to one 32-bit …
- AAAA Record — An AAAA record (DNS type 28, spoken "quad-A") maps a hostname to one 128-bit IPv6 …
- DoT (DNS over TLS) (DoT) — DNS over TLS (DoT) carries ordinary DNS messages inside a TLS connection on TCP port …