Technical notes by Jorge Marín

Rabbit hole 01: private DNS

| Reading time: 22 minutes
Copy permalink

Today I went a step further in reclaiming my freedom, and you can too.

Today I'll write about the Domain Name System (DNS), how to self-host your own server, and the advantages, disadvantages, and privacy trade-offs of different ways of resolving Internet hosts.

Problem statement
Your browsing might not be private, and others can decide what you can see and what you cannot while browsing the Internet.

What we learned
DNS, privacy, Internet censorship, DNS over HTTPS, DNS over TLS, Oblivious DNS over HTTPS, ECH
Evolution of the DNS ecosystem and related technologies. How to own your DNS infrastructure with some compromises.


Table of Contents


Summary

If you only care about my final recommendations, go to Appendix TL;DR

Brief DNS overview

Once upon a time, there was Internet. And so there was DNS, the Domain Name System.

DNS was designed to provide a human-readable naming system for network resources, mapping domain names such as myserver.com to resource records such as IP addresses that computers use to locate and communicate with those resources.

Your device is a stub resolver. It normally asks one recursive resolver. That resolver either has the answer cached or walks the DNS hierarchy: root → TLD → authoritative server.

The following schema shows the different servers involved in a typical resolution:

This system was designed a long time ago, and its main goal was not protecting users' privacy, but making name resolution work, fast and reliably. Traditional DNS queries and responses are normally sent in plaintext, which means they can be read or modified by networks, ISPs, or anybody able to monitor the relevant transmissions. Even if a website uses HTTPS, the DNS lookup itself is a separate operation and may still be exposed.

This lack of privacy has consequences for surveillance and censorship: whoever can observe or control DNS resolution can learn something about the domains users are trying to reach and can potentially interfere with resolution.

That trade-off — a fast, reliable system that was never built with privacy in mind — is where the practical problems start.

It's always DNS

ISPs and network operators can restrict access to websites by interfering with DNS resolution. This is often done when courts or regulators order domains to be blocked, although DNS is only one of several mechanisms that can be used for Internet censorship.

Public DNS services such as Google's 8.8.8.8 and Cloudflare's 1.1.1.1 made it possible to use a resolver other than the one provided by your ISP. This removed the ISP resolver as the only DNS chokepoint, but it did not remove the concept of a chokepoint.

You would now be trusting Google, Cloudflare, Quad9, or another provider to handle your requests. The question becomes how secure and private those centralized services are. The problem exists in at least two different dimensions:

Switching from ISP DNS to a public resolver can therefore change who you trust without eliminating trust.

Public resolvers can themselves be subject to legal orders or provider policies. Google, for example, documents jurisdiction-specific blocking behavior for its Public DNS service. The same general principle has appeared in legal disputes involving other public resolvers.

The lesson is simple: switching from your ISP to 8.8.8.8 or 1.1.1.1 moves the chokepoint. It does not remove it.

All of this shows that, as individuals, we no longer control which publicly available content we can access nor who might keep a record of our browsing activity.

That chokepoint is not just an abstract idea — it maps onto specific points in how DNS resolution actually works. The next section breaks those down.

Threat model

In more precise terms, there are two DNS hops, each with a different privacy problem:

TEXT
Client ───────────────► Recursive resolver
          HOP 1

Recursive resolver ───► Authoritative DNS
          HOP 2

Hop 1: Client → Recursive

We want to protect:

DNS queries from on-path observers such as ISPs or local networks The association between our identity and our queries at the recursive resolver

DoH, DoT, and DoQ encrypt the first part. ODoH addresses the second by separating the client's identity from the DNS request.

Hop 2: Recursive → Authoritative

We want to reduce or protect:

DNS information disclosed to authoritative servers — QNAME minimization reduces unnecessary disclosure DNS traffic from passive observers — encrypted recursive-to-authoritative transport can protect it where supported DNS answer authenticity and integrity — DNSSEC protects against forged or modified DNS data

We are not trying to achieve perfect anonymity. The goal is to control which party can see which information and reduce the number of parties we need to trust.

The rest of this post walks through the technologies that address each of these hops, and how they combine into a setup you can run and own yourself.

Technologies and ideas around DNS

Evolution

In a simplified way, this is the timeline of the DNS scene as new concepts and RFCs appeared over time:

  1. DNS (the baseline)

    • Plaintext and unauthenticated, usually resolved by whatever your ISP hands you
  2. Public DNS resolvers

    • Public recursive resolvers allowed you to use an alternative to your ISP
    • Anycast deployments can provide low-latency access from many locations
    • Providers advertise different combinations of speed, availability, privacy, filtering, and logging policies
  3. DNSSEC

    • Adds cryptographic signatures so a validating resolver can verify the authenticity and integrity of DNS data
    • DNSSEC does not encrypt DNS queries or hide which names are being queried
  4. QNAME minimization

    • Limits DNS query disclosure by sending only the minimum required domain labels to each authoritative nameserver, rather than the full QNAME
  5. DNS over TLS (DoT) / DNS over HTTPS (DoH) / DNS over QUIC (DoQ)

    • Encrypt DNS traffic between a DNS client and its resolver
    • DoT uses TLS over TCP
    • DoH transports DNS inside HTTPS
    • DoQ transports DNS over QUIC
  6. Oblivious DNS over HTTPS (ODoH)

    • stub → relay → target
    • The DNS request is encrypted before reaching the relay
    • The relay knows the source IP but cannot read the DNS request
    • The target can read the DNS request but sees the relay's address instead of the client's
  7. Unilateral Opportunistic Deployment of Encrypted Recursive-to-Authoritative DNS

    • Allows recursive resolvers to opportunistically use encrypted transport when communicating with authoritative servers
    • Falls back when encrypted transport is unavailable

DNS over HTTPS / DNS over TLS

Paraphrasing Cloudflare DNS article (highly recommended):

Think of a normal, unencrypted DNS query as being like a postcard sent through the mail: anyone handling the mail may happen to catch a glimpse of the text written on the back side, so it is not wise to mail a postcard that contains sensitive or private information.

DNS over TLS and DNS over HTTPS are two standards developed for encrypting plaintext DNS traffic in order to prevent malicious parties, advertisers, ISPs, and others from being able to interpret the data. Continuing the analogy, these standards aim to put an envelope around all postcards going through the mail, so that anyone can send a postcard without worrying that someone is snooping on what they are up to.

Basically, DNS over TLS (DoT) and DNS over HTTPS (DoH) both encrypt your DNS lookups, making it harder for others to see, change, or fake the DNS traffic between your device and the resolver.

DoH and DoT therefore solve a very specific problem: they protect the path to the resolver. They do not make the resolver blind to your DNS requests.

More information: Cloudflare DNS Article

Oblivious DNS over HTTPS

Oblivious DNS over HTTPS (ODoH) takes the privacy of DoH one step further: it separates your identity from your request so that no single party has access to both pieces of information at the same time.

With normal DoH, your DNS provider can still see “this IP address asked for this website.” The connection is encrypted, but the resolver terminates that encrypted connection and therefore sees both the client IP and the DNS query.

ODoH separates those two pieces of information. Your device encrypts the DNS request for the target resolver, then sends it through a relay. The relay can see your IP address, but cannot read the DNS request. The target can read the request, but sees the relay's address instead of yours.

The relay is therefore essential: ODoH needs both an ODoH relay and an ODoH target. They are designed so that neither one alone can see both your identity and your DNS queries.

ODoH is defined in RFC 9230, published in 2022. It is an Experimental RFC rather than an Internet Standards Track specification.

ODoH only provides its split-trust property when the relay and target do not collude or share enough information to reconstruct the association. If both parties are operated by the same organization, or their logs are combined, the privacy benefit can disappear.

A global/passive observer can still potentially correlate traffic patterns even though the relay and target individually cannot see both pieces of information.

Designing a private DNS infrastructure

We start with the original DNS concept. The main problems are:

Then we introduced public DNS services offered by large companies through globally distributed Anycast networks. These can provide better performance, availability, and an alternative to ISP-controlled resolution. We still have some important trust and privacy problems:

So we add DoH/DoT/DoQ, adding encryption to the client-to-resolver path. We still have:

So we configure ODoH, separating our identity from our request so that the relay and target do not individually have the complete picture. We still have:

At this point, the three issues boil down to one common obstacle: the centralized servers.

It is tempting to think that we can simply run our own recursive resolver and remove the public recursive resolver from the equation.

And we can.

A self-hosted recursive resolver can perform iterative resolution directly against the DNS hierarchy. It does not have to forward every query to another recursive resolver.

The pool of valid options so far:

  1. Forward queries to one or more public recursive resolvers while maintaining our own cache
  2. Use ODoH and separate our identity from the recursive resolver
  3. Resolve names ourselves by talking directly to root, TLD, and authoritative servers

Each option has a different trade-off.

Option #1: multiple recursive resolvers

Our server can query different recursive resolvers while maintaining a local cache.

No single public resolver necessarily gets our entire history, but our own server internet provider could still see our queries, unless DoH is used with each query. Each upstream resolver can also see the queries it receives from our server. Plus they are still vulnerable to attacks or changes of their terms and conditions that can compromise our privacy.

This distributes trust, but it does not provide cryptographic unlinkability. Correlation is still possible. No real strong anonymity.

Option #2: ODoH

We can accept the trade-offs and use ODoH.

Our self-hosted server becomes a local DNS proxy/forwarder. It can send the request through an ODoH relay to a target recursive resolver.

The relay sees our source IP but not the query. The target sees the query but sees the relay rather than our source IP.

This gives the strongest identity/query separation of the three approaches, but we now depend on the relay and target maintaining the separation.

Option #3: recursive resolution ourselves

We can configure our server to resolve domain names directly by walking the DNS hierarchy.

The source servers are the root, TLD, and authoritative DNS servers. These are distributed across many independently operated organizations and are not consumer recursive resolvers whose job is to maintain a user's query history. Though they can still see the source IP of your recursive resolver.

This approach gives us the most ownership, but it introduces another problem: the recursive-to-authoritative path.

After our resolver has the question, it still has to walk:

root → TLD → authoritative

That walk has traditionally used ordinary DNS transport. Plaintext recursion still exposes names to the network in front of your resolver. DoH, DoT, and ODoH were primarily designed for the first hop, from the client to a recursive resolver.

ODoH cannot simply be aimed at a root server: an ODoH target is a recursive DNS service, while root and TLD servers are authoritative servers.

A normal NS record gives us names and addresses for authoritative servers, not a DoH URL. A recursive resolver therefore cannot simply assume that the other side speaks HTTPS.

The recursive-to-authoritative hop has its own mechanisms, including DoT and DoQ. Most authoritative servers, however, still support traditional DNS on port 53, and a resolver cannot require encrypted transport from every authoritative server without risking failed resolutions.

This is where RFC 9539, Unilateral Opportunistic Deployment of Encrypted Recursive-to-Authoritative DNS, comes in.

RFC 9539 is the pragmatic workaround: a resolver can probe for encrypted DNS transport and use it when the authoritative server supports it, while retaining the ability to use ordinary DNS when it does not.

But that's the catch.

Opportunistic encryption does not mean encryption is guaranteed.

An active attacker can interfere with the encrypted connection attempt and cause the resolver to fall back to ordinary DNS. RFC 9539 primarily improves protection against passive monitoring; it does not provide robust protection against active attackers.

The resolver also cannot assume that every authoritative server on the Internet has upgraded. The RFC is designed around unilateral adoption: operators can deploy it without requiring the entire DNS ecosystem to coordinate first.

A few root-server operators have experimented with encrypted transport, but there is still no guarantee that a complete resolution path from root through TLD to authoritative server will be encrypted.

The point of RFC 9539 is therefore not “DNS is now encrypted end to end.” It is a phased rollout that allows encryption where possible without breaking resolution where it is not.

That leaves us with an important trade-off.

We can recurse ourselves and accept that some recursive-to-authoritative queries may still be visible on the wire.

Or we can forward with ODoH and let someone else perform the recursive work while separating our identity from the queries.

The setup below does the second.

Final setup and future

We need:

We can fulfill these requirements with ODoH.

We still need both a relay and a target recursive service that we trust to provide correct answers and respect the intended privacy separation. That is the compromise.

The advantage is that we can change the relay or target if we stop trusting our current choice.

My final setup looks like this:

TEXT
      Client
        │ DoH
 Self-hosted DNS
 proxy / forwarder
        │ ODoH
      Relay
        │ ODoH
 Global Public DNS
 Recursive Resolver
              │ DNS query (mostly plaintext DNS, maybe RFC 9539)
              ├── 1. Root ──────► "Which TLD?"
              │                    │
              │◄───────────────────┘
              ├── 2. TLD ───────► "Which authoritative server?"
              │                    │
              │◄───────────────────┘
              └── 3. Authoritative
                       ───────────► "Here is the final IP"
                       ◄───────────┘

The self-hosted component in this setup is not doing the recursive walk itself. It is providing local control over the DNS client side and forwarding the request through ODoH.

Who can see what?

The goal of the final architecture is not to make every component blind, but to split the information between them.

Participant Our IP DNS query
Local network / ISP Yes Not normally, if the client connection is encrypted
Self-hosted proxy Yes Yes
ODoH relay Yes No
ODoH target / recursive resolver No — sees the relay Yes
Authoritative DNS No — sees the recursive resolver Yes, for the names it receives

The key ODoH property is:

TEXT
Relay       → knows who is asking, but not what they ask
Target      → knows what is being asked, but not who originally asked

The self-hosted proxy is not part of this anonymity boundary: it can see both the client and the DNS request. Its purpose is to provide local control and forward the request through ODoH.

This separation depends on the relay and target not colluding or combining their information.

Bonus - ECH and RFC 9849

While researching ISP censorship, I came across another technique networks can use to restrict access to websites. It's called SNI / domain-based blocking.

Encrypted DNS only hides the lookup. The browser then opens a TLS connection to an IP address. Without ECH, the TLS ClientHello can expose the hostname through SNI.

A network that never saw the DNS query can therefore still learn the hostname and potentially block it.

ECH, defined in RFC 9849, encrypts the relevant TLS ClientHello information so that the hostname is no longer exposed to an on-path observer in the same way.

ECH does not hide the destination IP, does not replace DNS encryption, and requires support from both the client and the server.

The practical stack is therefore layered:

None of these mechanisms alone provides complete anonymity. They solve different parts of the problem.

Appendix 1 - TL;DR

For maximum privacy and ownership:

For not-so-strong privacy and full ownership:

For strong privacy and some ownership:

For convenience:


Note

Point your OS/browser/VPN to it:

  • Configure encrypted DNS at the layer that actually performs DNS resolution.
    • If your operating system supports system-wide DoH or DoT, configure it there.
    • Alternatively, configure a browser's DoH settings (better if it supports ODoH)
  • (optionally) Configure your VPN server to use those specific DNS servers See technical section on this post for steps on your operating system and browser.

Tip

Some open source, self-hosted options for DNS resolvers and DNS clients:

Not having encrypted DNS at the operating-system level means applications may use whatever DNS configuration is available to them, which might be plaintext. Browser DoH, a local stub (stubby, dnscrypt-proxy, Numa), or a VPN DNS setting can still encrypt.

Not having DoH configured in your browser means every webpage you visit with it will hit the DNS set by default, usually inherited from the operating system's resolver configuration, which might be plaintext.

Not having server ownership means your DNS requests will go through someone else's service. That service may or may not be private, may or may not log activity, and may be subject to filtering, legal orders, or other policies.

Appendix 2 - DoT and DoH implementation

Use system-wide encrypted DNS where your operating system supports it; use browser settings if it cannot inherit secure/private configuration from your operating system.

The exact menus vary by OS version.

Platform Protocol High-level setup
macOS 13+ DoT Install/create a DNS Settings configuration profile with DNSProtocol = TLS, your resolver IP(s), and its TLS hostname. macOS supports DoT natively.
Linux DoT Use systemd-resolved if available: configure a resolver with DNS= and DNSOverTLS=yes, then restart/enable systemd-resolved. Alternatively use stubby or dnscrypt-proxy.
Windows 11 DoT Don't use Windows' built-in encrypted DNS for DoT; current Windows settings are for DoH. For DoT, use a local resolver such as cloudflared, stubby, or another DoT-capable client, then point Windows DNS at 127.0.0.1.
iOS 16+ DoT Install a DNS configuration profile/app that uses Apple's DNS Settings framework with DNSProtocol = TLS, server IP(s), and ServerName. iOS supports system-wide DoT.
Android 9+ DoT Settings → Network & Internet → Private DNS → Private DNS provider hostname → enter your resolver's DoT hostname → Save.
Firefox DoH Settings → Privacy & Security → DNS over HTTPS → Advanced settings → choose Custom or Max Protection → select/enter your DoH provider.
Chrome DoH Settings → Privacy and security → Security → Use secure DNS → enable → choose current provider or custom provider.

System-level and browser-level encrypted DNS are not mutually exclusive. If a browser is configured to use its own DoH service, it may bypass the operating system's DNS configuration for its own queries.

If you want strict encryption, disable plaintext fallback where the relevant implementation offers that option. Be aware that some automatic encrypted-DNS modes intentionally fall back to ordinary DNS when the secure resolver cannot be reached.

Some examples

For Cloudflare:

TEXT
DoT hostname: cloudflare-dns.com / one.one.one.one / 1dot1dot1dot1.cloudflare-dns.com

IPv4:          1.1.1.1
               1.0.0.1

DoH URL:       https://cloudflare-dns.com/dns-query

For Quad9:

TEXT
DoT hostname: dns.quad9.net

IPv4:          9.9.9.9
               149.112.112.112

DoH URL:       https://dns.quad9.net/dns-query

Important distinction

Resources


UPDATE 1 (05/09/2026) Mullvad DNS shutdown