Type something to search...
What is DNS over HTTPS (DoH)?

What is DNS over HTTPS (DoH)?

DNS over HTTPS (DoH) is a protocol that sends DNS queries and responses inside ordinary encrypted HTTPS connections, instead of as plain-text packets on UDP or TCP port 53. Your device or browser sends each DNS question to a DoH server as an HTTP request, usually over port 443, and gets the answer back in the HTTP response. Because the traffic is encrypted with TLS and authenticated with the server's certificate, people on the network path, such as other users on public Wi-Fi or an intermediate network, can't read which names you look up or tamper with the answers. DoH is standardised in RFC 8484 and is supported by all major browsers, by Windows, macOS, iOS and Android, and by the large public resolvers.

Classic DNS was designed without any privacy or integrity protection, so every lookup reveals the sites and services you use to anyone who can see the traffic. DoH closes that gap for the hop between your device and your resolver. In this article you'll learn how DoH works at the protocol level, how to send DoH queries yourself with curl, dig and Python, how to turn it on in browsers and operating systems, how to run your own DoH server, and what it means for network administrators who rely on DNS for filtering and monitoring.

The Problem DoH Solves

When your device looks up a name over traditional DNS, the query travels unencrypted to a recursive resolver. Anyone who can see that traffic can:

  • See every name you look up, which reveals the websites, apps and services you use, even if the connections to those sites are encrypted with HTTPS.
  • Modify the answers, sending you to a different server or blocking a site by returning a fake "doesn't exist" response.
  • Redirect your queries to a different resolver without you knowing, which some networks do by intercepting all traffic on port 53.

DNSSEC can protect the integrity of answers for signed zones, but it doesn't hide what you're looking up. DoH protects both privacy and integrity for the connection between your device and the resolver.

How DoH Works

DoH carries normal DNS messages, in the standard binary wire format, inside HTTP requests. Nothing about the DNS message itself changes, only how it's transported.

  1. The client opens an HTTPS connection to the DoH server, for example https://cloudflare-dns.com/dns-query, and verifies the server's TLS certificate.
  2. It encodes the DNS query in wire format and sends it in an HTTP request.
  3. The server resolves the query like any recursive resolver would.
  4. It returns the DNS response in wire format in the body of the HTTP response.

The connection stays open, so later queries reuse it without a new TLS handshake. With HTTP/2 or HTTP/3, many queries can be in flight at once on a single connection.

GET and POST Requests

RFC 8484 defines two ways to send a query.

GET puts the wire-format query, encoded as base64url without padding, in a dns query parameter:

GET /dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB HTTP/2
Host: cloudflare-dns.com
Accept: application/dns-message

That string encodes a query for the A record of www.example.com. RFC 8484 recommends using a query ID of 0 with DoH, because a fixed ID makes identical GET requests cacheable by HTTP caches.

POST sends the raw wire-format query as the request body, with the Content-Type set to application/dns-message:

POST /dns-query HTTP/2
Host: cloudflare-dns.com
Content-Type: application/dns-message
Accept: application/dns-message
Content-Length: 33

<33 bytes of binary DNS query>

Both return the response with the media type application/dns-message, and caching is controlled with standard HTTP headers based on the TTLs in the answer.

JSON APIs

Some providers also offer a JSON interface that's handy for scripts and debugging. It isn't part of RFC 8484, so the exact format varies by provider, but Google and Cloudflare both support one.

Trying DoH Yourself

With curl and the JSON API

curl -s -H 'accept: application/dns-json' \
  'https://cloudflare-dns.com/dns-query?name=example.com&type=A' | jq
{
  "Status": 0,
  "TC": false,
  "RD": true,
  "RA": true,
  "AD": true,
  "CD": false,
  "Question": [
    { "name": "example.com", "type": 1 }
  ],
  "Answer": [
    { "name": "example.com", "type": 1, "TTL": 1726, "data": "192.0.2.10" }
  ]
}

Status: 0 means NOERROR, and AD: true means the resolver validated the answer with DNSSEC. Google's equivalent is at https://dns.google/resolve?name=example.com&type=A.

With curl and the Wire Format

You can send an RFC 8484 GET request directly, using the encoded query from earlier, and inspect the binary response:

curl -s -H 'accept: application/dns-message' \
  'https://cloudflare-dns.com/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' |
  xxd | head -n 4

The output is a raw DNS message, the same bytes a resolver would send over UDP. It's not very readable, which is why tools like dig are more convenient.

With curl as a DoH Client

curl can also use DoH for its own name resolution, so the lookup of the site you're fetching goes over HTTPS:

curl --doh-url https://dns.google/dns-query -sI https://www.example.com/ | head -n 1

This is a quick way to check whether DoH resolution works from a particular network.

With dig and kdig

BIND 9.18 and later include DoH support in dig with the +https option:

dig @1.1.1.1 +https www.example.com A
;; ANSWER SECTION:
www.example.com.        300     IN      A       192.0.2.80

;; Query time: 18 msec
;; SERVER: 1.1.1.1#443(1.1.1.1) (HTTPS)

The SERVER line shows port 443 and the HTTPS transport. Knot's kdig offers the same:

kdig @1.1.1.1 +https www.example.com A

With Python

dnspython supports DoH through dns.query.https, which needs the httpx package:

#!/usr/bin/env python3
"""Look up a name over DNS over HTTPS."""
import sys

import dns.message
import dns.query
import dns.rdatatype

name = sys.argv[1] if len(sys.argv) > 1 else "www.example.com"
query = dns.message.make_query(name, dns.rdatatype.A)
query.id = 0  # RFC 8484 recommends ID 0 for cacheability

response = dns.query.https(query, "https://cloudflare-dns.com/dns-query", timeout=5)

for rrset in response.answer:
    print(rrset.to_text())
pip install "dnspython[doh]"
python3 doh_lookup.py www.example.com
www.example.com. 300 IN A 192.0.2.80

Enabling DoH on Your Devices

Browsers

  • Firefox: Go to Settings > Privacy & Security > DNS over HTTPS, and choose Default, Increased or Max Protection, along with a provider. In some regions, Firefox enables DoH by default.
  • Chrome and Edge: Go to Settings > Privacy and security > Security > Use secure DNS. By default, Chrome upgrades to DoH automatically if your current resolver is a known provider that supports it, and you can also choose a specific provider or enter a custom DoH URL.
  • Safari: Uses the operating system's DNS settings, including any encrypted DNS configured through a profile.

Windows 11

Windows 11 supports DoH natively. In Settings > Network & internet, open your connection's properties, edit the DNS server assignment, enter a resolver that Windows recognises as supporting DoH, and set DNS over HTTPS to On. You can see the resolvers Windows knows about in PowerShell:

Get-DnsClientDohServerAddress

To add your own DoH resolver to that list:

Add-DnsClientDohServerAddress -ServerAddress 192.0.2.53 `
  -DohTemplate 'https://dns.example.com/dns-query' `
  -AllowFallbackToUdp $false -AutoUpgrade $true

Setting -AllowFallbackToUdp $false stops Windows falling back to plain DNS if the DoH server is unreachable, which is more private but means lookups fail outright in that case.

macOS and iOS

Apple platforms support encrypted DNS through configuration profiles that use the DNS Settings payload, or through apps that use the system's network extension APIs. Public resolver providers publish ready-made profiles, and organisations can deploy them through mobile device management.

Android

Android's Private DNS setting uses DNS over TLS rather than DoH, although some apps and browsers on Android use DoH independently.

Running Your Own DoH Server

If you'd rather not send your queries to a public provider, you can serve DoH from your own resolver. Recent versions of Unbound can serve DoH directly:

server:
    interface: 0.0.0.0@443
    interface: ::0@443
    https-port: 443
    http-endpoint: "/dns-query"
    tls-service-key: "/etc/unbound/tls/privkey.pem"
    tls-service-pem: "/etc/unbound/tls/fullchain.pem"

    access-control: 192.0.2.0/24 allow
    access-control: 2001:db8:100::/48 allow

Unbound must be built with libnghttp2 for DoH support. Check with:

unbound -V | grep -i nghttp2

Use a certificate for a hostname such as dns.example.com from a public certificate authority, so clients can verify it, and restrict access-control to the networks you serve. Running an open DoH resolver on the internet carries the same abuse risks as any open resolver. Other options include BIND 9.18 and later, which can serve DoH natively, or a DoH proxy in front of an existing resolver.

Test your server from a client:

dig @dns.example.com +https www.example.com A

Discovering DoH Automatically

Configuring a DoH URL by hand isn't practical on every network, so newer standards help clients find encrypted resolvers automatically:

  • DDR (Discovery of Designated Resolvers, RFC 9462) lets a client ask its current resolver, using a special _dns.resolver.arpa query for an SVCB record, whether it also offers DoH or another encrypted protocol.
  • DNR (Discovery of Network-designated Resolvers, RFC 9463) lets networks advertise encrypted resolvers through DHCP and IPv6 router advertisements.

You can see whether a resolver advertises DDR:

dig @1.1.1.1 _dns.resolver.arpa SVCB +short
1 one.one.one.one. alpn="h2,h3" port=443 ipv4hint=1.1.1.1,1.0.0.1 ipv6hint=2606:4700:4700::1111,2606:4700:4700::1001 key7="/dns-query{?dns}"
2 one.one.one.one. alpn="dot" port=853 ipv4hint=1.1.1.1,1.0.0.1 ipv6hint=2606:4700:4700::1111,2606:4700:4700::1001

The first record advertises DoH, with the dohpath (shown here as key7 by some versions of dig) giving the URL template. Windows and Apple platforms use DDR to upgrade to encrypted DNS when the resolver supports it.

DoH on Managed Networks

DoH is great for privacy on untrusted networks, but it can get in the way on networks that rely on DNS for security. If a browser sends queries straight to a public DoH provider, they bypass the organisation's resolver, its filtering, and its logs.

There are well-established ways to manage this:

  1. Use policies: Chrome, Edge and Firefox all support enterprise policies to disable DoH or point it at your own resolver. For Chrome, the DnsOverHttpsMode policy controls this, and Firefox uses the DNSOverHTTPS policy.
  2. Offer your own DoH: Run DoH on your internal resolver and push its URL to devices, so you keep encryption and visibility.
  3. Use the Firefox canary domain: Firefox checks use-application-dns.net. If your resolver returns NXDOMAIN for that name, Firefox doesn't enable DoH by default on that network. It doesn't override a user's explicit choice.
  4. Block known public DoH endpoints at the firewall, with care. DoH runs on port 443 and looks like other HTTPS traffic, so blocking relies on lists of known DoH servers and will never be complete.

In Unbound, you can answer the canary domain with NXDOMAIN like this:

server:
    local-zone: "use-application-dns.net." always_nxdomain

Check that it's working:

dig use-application-dns.net A | grep status
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 51884

What DoH Doesn't Do

It's worth being clear about DoH's limits:

  • It only protects the hop to your resolver. The resolver itself sees every query, so you're trusting whichever DoH provider you choose. The resolver's own lookups to authoritative servers are usually still unencrypted.
  • It doesn't hide the sites you visit entirely. After the lookup, your device connects to the site's IP address, and unless Encrypted Client Hello is in use, the site's name is still visible in the TLS handshake.
  • It doesn't authenticate the DNS data itself. DoH proves you're talking to the right resolver, but only DNSSEC proves the records came from the domain owner.

DNS over TLS (DoT) protects the same hop with a dedicated port, 853, rather than blending in with web traffic on port 443. Both are valid choices, and many resolvers support both.


FAQ: DNS over HTTPS

Yes, for the connection between your device and the resolver. DoH encrypts your queries so others on the network can't read or alter them. You still need to trust the DoH provider, and DNSSEC is still needed to verify the records themselves.

Usually not noticeably. The first connection needs a TLS handshake, but it's reused for later queries, and a well-run DoH provider close to you can be as fast as, or faster than, an ISP resolver.

Your ISP can no longer see your DNS queries, but it can still see the IP addresses you connect to. Without Encrypted Client Hello, it may also see site names in the TLS handshake.

DoH normally uses TCP port 443, the same as regular HTTPS, or UDP port 443 when HTTP/3 is used. That makes it hard to distinguish from other web traffic.

Several public resolvers offer a test page that shows whether your browser is using their DoH service, such as Cloudflare's test at one.one.one.one/help. In Firefox, the about:networking page also shows DNS details.

They can manage it through browser and operating system policies, answer the Firefox canary domain with NXDOMAIN, and block known DoH endpoints. The most effective approach is usually to offer an internal DoH resolver and enforce it by policy.

It makes sense if you want encrypted DNS without trusting a third party, or if you manage a network and want to keep filtering and logging. Restrict access to your own clients so you don't create an open resolver.


Conclusion

DNS over HTTPS wraps ordinary DNS messages in encrypted HTTPS connections, so the names you look up are hidden from the network and the answers can't be tampered with on the way to your device. It's built on the same HTTP and TLS technology as the rest of the web, which is why browsers and operating systems have been able to adopt it so widely, and why it's easy to try with curl, dig +https or a few lines of Python.

Turn it on for devices that use untrusted networks, choose a resolver you trust, and remember that it protects the hop to the resolver rather than the whole journey. If you manage a network, embrace it rather than fight it: run your own DoH resolver, publish it to your devices through policy, and you keep both privacy for users and the visibility your security tools rely on.

Tags :
Share :

Related Posts

What is the difference between an A record and a CNAME record?

What is the difference between an A record and a CNAME record?

The difference between an A record and a CNAME record is what they point to. An A record points a hostname directly at an IPv4 address, such

Dive Deeper
What are the best DNS providers for websites?

What are the best DNS providers for websites?

The best DNS providers for most websites are Cloudflare for a fast, free, easy starting point, Amazon Route 53 if you already run on AWS, **G

Dive Deeper
What are the best public DNS resolvers?

What are the best public DNS resolvers?

The best public DNS resolvers for most people are Cloudflare (1.1.1.1) for speed and privacy, Google Public DNS (8.8.8.8) for reliability and

Dive Deeper