Guides » Network Security » Ultimate DNS Privacy Guide

Ultimate DNS Privacy Guide

DNS is the phonebook of the internet — every time your browser resolves a domain name, that query goes to your configured DNS resolver. The default transport is the issue: the query goes out unencrypted on port 53. Your ISP, your hotel Wi-Fi, and anyone running a packet sniffer on the same network can see every site you visit before you even load the first page.

The stack below came out of a network privacy audit we ran in 2024. Encryption worked the first time; the surprises were all downstream of it. A browser had been pointed at its own DoH provider and was ignoring the system resolver, a phone kept reverting to carrier DNS the moment it left Wi-Fi, and one machine's resolver config was getting silently rewritten by its DHCP client after each reboot. Defaults like that are not malfunctions. They are what you get when the system was not built assuming a listener.

1. Network Architecture & Data Flow

A typical Linux workstation or server delegates name resolution to systemd-resolved, whose full behavior is set in /etc/systemd/resolved.conf.

# Edit the resolver configuration
$ sudo nano /etc/systemd/resolved.conf

[Resolve]
DNS=1.1.1.1#cloudflare-dns.com 9.9.9.9#dns.quad9.net
FallbackDNS=8.8.8.8#dns.google
DNSSEC=true
DNSOverTLS=yes
Cache=yes

After saving, restart the resolver and verify the status:

$ sudo systemctl restart systemd-resolved
$ resolvectl status

Each line in the status output confirms a layer of protection. The key ones to check: DNSSEC: yes, DNS Over TLS: yes, and the DNS Servers line pointing at your chosen encrypted resolver — not the ISP default.

Terminal output showing dig @1.1.1.1 example.com +dnssec: query returns 93.184.216.34 with AD bit set confirming DNSSEC validation passed and DNS query was encrypted over TLS
Figure 1: Real dig output confirming DNSSEC validation. The ad (authenticated data) flag confirms cryptographic verification against the root trust anchor. Resolver 1.1.1.1 reached over TLS port 853.

For applications that ignore the system resolver (Firefox, custom VPN clients), configure DoH directly:

# Firefox about:config — set these prefs:
network.trr.mode = 5          # 5 = TRR first, no fallback
network.trr.uri = https://mozilla.cloudflare-dns.com/dns-query
network.trr.custom_uri = https://mozilla.cloudflare-dns.com/dns-query
Terminal output showing resolvectl status: DNS over TLS enabled, DNSSEC enabled, DNS servers set to 1.1.1.1 and 9.9.9.9, resolved.conf contents with DNSSEC=true and DNSOverTLS=yes
Figure 2: Real resolvectl status output confirming encrypted DNS. System reports DNS over TLS: yes and DNSSEC: yes. /etc/systemd/resolved.conf shows Cloudflare and Quad9 as encrypted resolvers.

Step 2: Network-Wide Blocking with Pi-hole

Pi-hole blocks ads and trackers at the network level by acting as a sinkhole DNS resolver for your entire local network.

# Deploy Pi-hole via Docker
$ docker run -d \
  --name=pihole \
  --network=host \
  --cap-add=NET_ADMIN \
  -e WEBPASSWORD='Str0ngP@ss!' \
  -v pihole-etc:/etc/pihole \
  -v pihole-dnsmasq:/etc/dnsmasq.d \
  pihole/pihole:latest

After deployment, configure your router's DHCP settings to point all clients to the Pi-hole IP. Confirm blocking with a packet capture:

# Capture all DNS traffic (plaintext and encrypted)
$ sudo tcpdump -i any -n '(port 53 or port 853)' -c 10

If you see traffic to port 53 reaching ISP resolver IPs (like 192.168.1.1 or a carrier-grade address), that is a plaintext leak. Encrypted DNS traffic should only appear on port 853, destined for your chosen resolver (1.1.1.1, 9.9.9.9, or 8.8.8.8).

Terminal output showing sudo tcpdump -i any filtering port 53 and 853: all packets go to 1.1.1.1:853 and 9.9.9.9:853 (DNS-over-TLS), zero plaintext port 53 traffic — confirming no DNS leaks
Figure 3: Real tcpdump capture confirming no plaintext DNS leaks. All 4 captured packets are on port 853 (DNS-over-TLS) destined for Cloudflare (1.1.1.1) and Quad9 (9.9.9.9). Zero traffic on port 53.

2. Protocol & Configuration Deep-Dive

Verification must happen on the wire, not in theory. Before trusting the setup, confirm the configured DNS server is active, blocking rules are applied, and no client bypasses the resolver by falling back to the default gateway.

Threat Vector Impact Remediation Action
Local DNS Cache Poisoning Stub resolver returns wrong records from poisoned cache Flush local cache with resolvectl flush-caches; validate with dig.
Split-Tunnel Bypass Firefox, VPN clients, or Docker bypass DoH/DoT Lock /etc/resolv.conf with chattr +i; disable the automatic fallback to DHCP resolvers; audit each application's resolver behavior separately.
TLS Certificate Pinning Failure DoT handshake aborts on expired resolver cert Use resolver hostname with valid certs; prefer DoH for more flexible cert handling.

3. Traffic Verification & Leak Testing

  • Confirm DNSOverTLS=yes and DNSSEC=true in resolved.conf. Read each line of resolvectl status.
  • Lock /etc/resolv.conf with chattr +i to prevent overwrite by NetworkManager or DHCP client.
  • Run a 60-second tcpdump capture filtering for port 53. No packets should reach ISP resolver.
  • Back up resolver config and resolved.conf before modifying.
  • Disable unused local caches — systemd-resolved, dnsmasq, unbound running in parallel can route queries outside DoT.
  • Validate Firefox DoH — check about:networking for TRR status.
  • Reboot and re-verify — DHCP renewals and package updates can revert DNS settings.

The difference between a working encrypted DNS setup and a fragile one is that single bypass path you forgot to close. The packet capture tells you if queries are leaving over TLS; the resolver status tells you the system is using your chosen provider; the Firefox check tells you no application is overriding the system-level configuration. Treat every layer as pass/fail.

4. Troubleshooting Failure Modes

Will encrypted DNS slow down browsing?

DoT and DoH add a single TLS handshake (one round trip). Cloudflare 1.1.1.1 responds in under 10 ms. The bigger risk is a misconfigured local cache that bypasses encryption — fix that first.

Can I use encrypted DNS with a VPN?

Yes, but configure both layers explicitly. Some VPN clients route DNS through the tunnel (good); others leave it split (bad). After connecting, run tcpdump to confirm DNS goes to your encrypted resolver.

Does this work on Android or iOS?

Android 9+: Settings > Network > Private DNS = dns.google or 1dot.oisd.dev. iOS 14+: Settings > Wi-Fi > Configure DNS. Both still need verification after updates.

Sources & References


Tested on Ubuntu 24.04 LTS and Debian 12. Our own machines carried this process end to end; the outputs below are first-hand captures. DNS configurations vary by OS version and network environment.