Privacy Tools Guide

By default, DNS queries on Linux go to your ISP’s resolver in plaintext on UDP port 53. Anyone between you and that resolver — your ISP, your network admin, a rogue router — can log every domain you visit. DNS over HTTPS (DoH) encrypts those queries inside standard HTTPS traffic on port 443.

This guide covers three approaches: the built-in systemd-resolved (no extra software), dnscrypt-proxy (flexible, supports filters), and AdGuard Home (self-hosted with a web UI).

Method 1: systemd-resolved with DoH

Most modern Debian/Ubuntu and Fedora systems already use systemd-resolved. Check:

systemctl status systemd-resolved
resolvectl status | head -20

Enable DNS over HTTPS in systemd-resolved

Edit the resolved configuration:

sudo nano /etc/systemd/resolved.conf

Add or modify:

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

DNS= accepts IP#hostname format. The #hostname part is used to verify the TLS certificate.

Restart resolved:

sudo systemctl restart systemd-resolved

Verify DoH is active:

resolvectl status | grep -E "(DNS Server|DNS over TLS|DNSSEC)"

Expected output:

Current DNS Server: 1.1.1.1#cloudflare-dns.com
DNS over TLS setting: yes
DNSSEC setting: yes

Test a lookup and confirm it works:

resolvectl query example.com

Confirm No Plaintext DNS Leaks

Capture traffic to check that port 53 traffic is gone:

sudo tcpdump -i any port 53 -c 20 &
dig example.com

You should see no port 53 traffic if DoH is working correctly. All queries should appear on port 443.

Method 2: dnscrypt-proxy

dnscrypt-proxy supports DoH, DNSCrypt, and ODoH (Oblivious DoH). It runs as a local resolver on 127.0.0.1:53 and proxies queries through encrypted channels.

Install dnscrypt-proxy

# Debian/Ubuntu
sudo apt install dnscrypt-proxy

# Fedora
sudo dnf install dnscrypt-proxy

# Arch
sudo pacman -S dnscrypt-proxy

Configure dnscrypt-proxy

sudo nano /etc/dnscrypt-proxy/dnscrypt-proxy.toml

Key settings to configure:

# Listen on localhost port 53
listen_addresses = ['127.0.0.1:53', '[::1]:53']

# Use only DoH servers (not plain DNS)
server_names = ['cloudflare', 'quad9-doh-ip4-filter-pri', 'nextdns']

# Filter out servers without DNSSEC
require_dnssec = true

# Filter out servers that log queries
require_nolog = true

# Filter out servers that don't require NOFILTER
require_nofilter = false

# Block ads and trackers with built-in blocklists
[sources]
  [sources.public-resolvers]
  urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md']
  cache_file = '/var/cache/dnscrypt-proxy/public-resolvers.md'
  minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
  refresh_delay = 72

# Enable CLOAKING for local overrides (optional)
# [cloaking]
# cloaking_rules = '/etc/dnscrypt-proxy/cloaking-rules.txt'

# Block known malware/ad domains
[blocked_names]
blocked_names_file = '/etc/dnscrypt-proxy/blocked-names.txt'

Start and enable the service:

sudo systemctl enable --now dnscrypt-proxy

Point systemd-resolved at dnscrypt-proxy

Edit resolved.conf to use the local proxy:

sudo nano /etc/systemd/resolved.conf
[Resolve]
DNS=127.0.0.1
DNSOverTLS=no
DNSSEC=no

(dnscrypt-proxy handles DNSSEC and encryption itself.)

Restart both services:

sudo systemctl restart dnscrypt-proxy systemd-resolved

Test:

dig @127.0.0.1 example.com

Check which server is actually being used:

dnscrypt-proxy -resolve example.com

Method 3: AdGuard Home (Self-Hosted)

AdGuard Home is a DNS server with DoH support, ad blocking, and a web interface. Good for households or small networks.

Install AdGuard Home

curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

The installer places the binary in /opt/AdGuardHome/. Access the setup wizard at http://localhost:3000.

During setup:

Configure DoH Upstream in AdGuard Home

In the web UI, go to Settings > DNS settings > Upstream DNS servers:

https://dns.cloudflare.com/dns-query
https://dns.quad9.net/dns-query
https://dns.adguard-dns.com/dns-query

Enable Parallel requests for faster lookups.

Set your system DNS to 127.0.0.1:

sudo resolvectl dns eth0 127.0.0.1

Or edit /etc/resolv.conf directly (if not managed by systemd-resolved):

echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf

Lock the file against NetworkManager overwrites:

sudo chattr +i /etc/resolv.conf

Choosing a DoH Provider

Provider Logs DNSSEC Filtering Notes
Cloudflare (1.1.1.1) No query logs Yes Optional Fast, widely audited
Quad9 (9.9.9.9) No PII Yes Malware blocking Swiss nonprofit
NextDNS Configurable Yes Highly configurable Free tier available
AdGuard DNS Minimal Yes Ad/tracker blocking Self-hostable

Avoid using your ISP’s or Google’s DNS for privacy — they log queries.

Verify the Full Setup

Check DNS resolution is working:

nslookup example.com
curl -s "https://www.dnsleaktest.com/results.json" | python3 -m json.tool | grep name

Run a DNS leak test at https://dnsleaktest.com — all results should show your chosen provider, not your ISP.

Confirm DNSSEC validation:

dig +dnssec sigfail.verteiltesysteme.net
# Should return SERVFAIL if DNSSEC validation is working

Troubleshooting Common Issues

DNS Resolution Fails After Configuration

If you lose DNS resolution after enabling DoH, the most likely cause is a configuration syntax error:

# Temporary fix: use a direct DNS server
echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf

# Then review your configuration files for typos
sudo journalctl -u systemd-resolved --no-pager -n 50

Slow DNS Lookups

DoH adds TLS overhead compared to plain DNS. If lookups feel slow, check latency:

time dig @1.1.1.1 example.com
time dig @9.9.9.9 example.com
time dig @8.8.8.8 example.com

Choose the provider with the lowest latency from your location. Cloudflare consistently provides the fastest response times due to its CDN presence.

NetworkManager Overwriting resolv.conf

NetworkManager frequently overwrites /etc/resolv.conf. Prevent this:

# /etc/NetworkManager/conf.d/dns.conf
[main]
dns=systemd-resolved

Then restart: sudo systemctl restart NetworkManager

Performance Comparison: DoH vs Standard DNS

Metric Standard DNS (UDP 53) DNS over TLS DNS over HTTPS
First lookup latency ~20ms ~80ms ~100ms
Cached lookup latency ~1ms ~1ms ~1ms
Privacy from ISP None Full Full
Resistance to blocking None Moderate (port 853) High (port 443)
CPU overhead Minimal Low Low-Medium

The first lookup is slower with DoH due to the TLS handshake, but subsequent lookups use cached connections and perform comparably.

Built by theluckystrike — More at zovo.one