Your ISP Is Still Reading Your DNS Queries
dnscrypt-proxy wins for most home labs by avoiding single-provider lock-in, and it’s now the only one of the two that actually works: Cloudflare removed cloudflared’s DNS-over-HTTPS forwarding mode outright in version 2026.2.0.
You’ve got Pi-hole running. Ads are blocked. You feel like a network wizard. And then you remember: every DNS query your Pi-hole forwards upstream goes out completely unencrypted. Your ISP can read every hostname your household resolves. So can anyone else sitting between you and your upstream resolver.
DNS-over-HTTPS (DoH) is the fix. Specifically, the two tools you’ll actually use to set it up at home: cloudflared and dnscrypt-proxy.
Both sit between your local resolver (Pi-hole, AdGuard Home, Unbound) and the public internet, wrapping your queries in HTTPS or other encrypted transports before they leave your network. But they’re built with very different philosophies, and choosing the wrong one means either unnecessary complexity or unnecessary lock-in.
Let’s walk through both, set them up, and figure out which one belongs in your homelab.
What We’re Actually Solving
Before picking a tool, be honest about your threat model.
DoH protects you from:
- Your ISP logging and selling your DNS query history
- Passive surveillance on your local network (coffee shop, hotel, nosy router firmware)
- DNS hijacking by your ISP redirecting certain queries
DoH does NOT protect you from:
- The upstream resolver you’re sending queries to. They still see everything.
- TLS SNI leaking the hostname when you actually connect to a site (unless your browser/OS does Encrypted Client Hello)
- A compromised Pi-hole or router inside your own network
So the honest answer is: DoH hides your queries from your ISP and local eavesdroppers, but not from whoever runs the upstream resolver you’re using. Keep that in mind when choosing a provider.
Which One Should Actually Sit In Front Of Pi-hole?
- Pick dnscrypt-proxy either way: it’s the only one of the two that still does DNS-over-HTTPS forwarding. Choose your own upstream resolver (including Cloudflare’s, if that’s what you want), get automatic latency-based failover across multiple servers, and ODoH’s relay-based anonymization if you want it.
- cloudflared is no longer an option for this job. Cloudflare pulled the feature that made this comparison possible in the first place.
Option 1: cloudflared
cloudflared is Cloudflare’s official tunnel client. It used to ship a proxy-dns mode that turned it into a local DoH forwarder, simple, opinionated, and speaking only to Cloudflare’s resolvers.
That mode is gone. Cloudflare removed proxy-dns entirely in cloudflared 2026.2.0. Run the command below on any current build and it exits immediately with dns-proxy feature is no longer supported, cloudflared’s own source points you at Cloudflare’s DNS-over-HTTPS client docs instead of offering a replacement binary. cloudflared is still fine for Tunnels and Zero Trust, it just can’t do this job anymore. The install and run steps below are kept for context (and for anyone deliberately pinning an older release), but if you want Cloudflare’s resolvers specifically, skip ahead and point dnscrypt-proxy at cloudflare instead.
Install
# Debian/Ubuntuwget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.debsudo dpkg -i cloudflared-linux-amd64.deb
# Or via package manager on some distrossudo apt install cloudflaredRun It
cloudflared proxy-dns --port 5053 --upstream https://1.1.1.1/dns-query --upstream https://1.0.0.1/dns-queryOn a pre-2026.2.0 build, this would listen on 127.0.0.1:5053 and forward queries over DoH to Cloudflare’s 1.1.1.1. On any current release, it just errors out. Point your Pi-hole at dnscrypt-proxy instead (below) if you’re setting this up today.
Systemd Unit
You don’t want to babysit this in a terminal. Drop a unit file:
sudo cloudflared service installsudo systemctl enable --now cloudflaredOr write your own if you want custom flags:
[Unit]Description=cloudflared DNS-over-HTTPS proxyAfter=network-online.targetWants=network-online.target
[Service]ExecStart=/usr/bin/cloudflared proxy-dns \ --port 5053 \ --upstream https://1.1.1.1/dns-query \ --upstream https://1.0.0.1/dns-queryRestart=on-failureUser=nobodyDynamicUser=yes
[Install]WantedBy=multi-user.targetSave that to /etc/systemd/system/cloudflared.service, then:
sudo systemctl daemon-reloadsudo systemctl enable --now cloudflaredPoint Pi-hole at It
In Pi-hole’s admin panel: Settings → DNS → Custom upstream DNS servers. Add:
127.0.0.1#5053Uncheck all other upstreams. Done.
For AdGuard Home: Settings → DNS Settings → Upstream DNS servers → add 127.0.0.1:5053.
Verify It Works
dig @127.0.0.1 -p 5053 example.comYou should get a real answer. To confirm it’s actually going out encrypted:
sudo tcpdump -i lo port 5053 -nTraffic on port 5053 is the plain DNS between Pi-hole and cloudflared. That’s fine, it’s localhost. The outbound encryption happens on port 443 toward Cloudflare. To verify that:
sudo tcpdump -i eth0 host 1.1.1.1 -nYou should see only port 443 traffic, no port 53.
The Honest Limitation
Even before Cloudflare pulled proxy-dns, cloudflared was Cloudflare or bust: the binary is built and maintained by Cloudflare, optimized for their infrastructure, and their documentation basically assumed you were using 1.1.1.1. If you wanted Quad9, Mullvad, or your own resolver, you were swimming against the current even when the feature existed.
Also worth remembering if you ever run an older pinned build: using cloudflared this way means Cloudflare knows everything your household resolves. You’d be trading your ISP’s surveillance for Cloudflare’s. They have a decent privacy policy, but that’s still a significant trust decision, one more reason dnscrypt-proxy is the only real option going forward.
Option 2: dnscrypt-proxy
dnscrypt-proxy is the Swiss Army knife of encrypted DNS. It supports DoH, DoT (DNS-over-TLS), DNSCrypt (its own encrypted protocol), and ODoH (Oblivious DoH, which we’ll look at shortly). It ships with a curated list of public resolvers, does automatic load balancing, timeout-based failover, and doesn’t care which provider you use.
This is the one that actually solves provider lock-in.
Install
# Debian/Ubuntusudo apt install dnscrypt-proxy
# Or grab the binary directlywget https://github.com/DNSCrypt/dnscrypt-proxy/releases/latest/download/dnscrypt-proxy-linux_x86_64-2.x.x.tar.gzThe package version in most distros is a bit behind but functional. The GitHub release is always current.
Configure It
The main config lives at /etc/dnscrypt-proxy/dnscrypt-proxy.toml. It’s heavily commented and intimidating, but you only need to touch a handful of settings.
# Listen on localhost port 5053 so Pi-hole can still own port 53listen_addresses = ['127.0.0.1:5053']
# Pick your resolvers from the public list# Options: quad9-dnscrypt-ip4-filter-pri, mullvad-doh, adguard-dns-doh, cloudflare, etc.server_names = ['quad9-dnscrypt-ip4-filter-pri', 'mullvad-doh', 'adguard-dns-doh']
# Require servers that don't log queriesrequire_nolog = true
# Require servers that don't filter results (unless you want filtering)require_nofilter = false
# Only use resolvers that support DNSSEC (validation still happens upstream,# not locally — pair with Unbound if you want local validation)require_dnssec = true
# Load balance across multiple serverslb_strategy = 'p2' # pick 2 fastestlb_estimator = true
# Automatic resolver list updates[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 prefix = ''Then enable and start it:
sudo systemctl enable --now dnscrypt-proxyOblivious DoH (ODoH) The Actually Interesting Part
Regular DoH still tells the upstream resolver your IP address. Oblivious DoH (ODoH) adds a relay in between: your client encrypts the query such that only the target resolver can decrypt it, but routes it through an oblivious relay that strips your IP. The relay sees your IP but not the query. The resolver sees the query but not your IP. Neither one has the full picture.
This is the closest you get to actual privacy from the upstream resolver, without routing everything through Tor.
To enable ODoH in dnscrypt-proxy:
# Add ODoH relays[anonymized_dns] routes = [ { server_name = 'odoh-cloudflare', via = ['odohrelay-crypto-sx'] }, { server_name = 'odoh-crypto-sx', via = ['odohrelay-numa'] } ]The relay and target are operated by different organizations, so collusion would be required to de-anonymize you. Honestly, for a home lab, this is probably overkill, but it’s a cool protocol and dnscrypt-proxy is one of the few clients that supports it out of the box.
DNS-over-Tor
Yes, dnscrypt-proxy can route queries through Tor if you have a SOCKS5 proxy running locally (Tor Browser, tor service, etc.):
[proxy] proxy = 'socks5://127.0.0.1:9050'This adds significant latency (Tor is not fast) and is way overkill for most home setups, but it’s there if you need it.
Point Pi-hole at dnscrypt-proxy
Same as cloudflared: in Pi-hole’s DNS settings, set the upstream to 127.0.0.1#5053. For AdGuard Home, use 127.0.0.1:5053.
Verify
# Check it's listeningsudo ss -ulnp | grep 5053
# Query through itdig @127.0.0.1 -p 5053 example.com
# Check which server actually answereddig @127.0.0.1 -p 5053 example.com +stats | grep SERVER
# Watch the traffic (plain DNS on loopback — fine)sudo tcpdump -i lo port 5053 -nFor the upstream verification, dnscrypt-proxy logs which server handled each query at debug log level:
sudo journalctl -u dnscrypt-proxy -fHead-to-Head
The cloudflared column below describes the proxy-dns mode Cloudflare removed in version 2026.2.0. It’s here for comparison and for anyone pinning an old release, not as a live option.
| Feature | cloudflared (pre-2026.2.0) | dnscrypt-proxy |
|---|---|---|
| Setup complexity | Very low | Moderate |
| Provider lock-in | Cloudflare only | Any provider |
| Protocols | DoH | DoH, DoT, DNSCrypt, ODoH |
| ODoH support | No | Yes |
| DNS-over-Tor | No | Yes |
| Automatic failover | Basic (two upstreams) | Yes, with latency-based lb |
| Memory footprint | ~20 MB | ~15 MB |
| Curated resolver list | No | Yes (auto-updated) |
| Pi-hole integration | Trivial | Trivial |
| AdGuard integration | Trivial | Trivial |
| DNSSEC validation | Passed to upstream | Passed to upstream (require_dnssec only filters servers) |
| Active development | Yes (Cloudflare) | Yes (open source) |
Memory footprint is roughly equivalent; both are lightweight enough that you’d run them happily on a Pi Zero. Latency depends far more on your upstream resolver and your internet connection than on which forwarder you choose.
A Note on Unbound
If you’re running Unbound as your recursive resolver (doing the full DNS resolution chain yourself instead of forwarding to a public resolver), you don’t need either of these tools. Unbound speaks to root servers directly, and you can configure it to do DoT toward individual zones.
But if you’re forwarding to a public resolver (which most Pi-hole and AdGuard setups do), you need one of these two to encrypt that hop.
The Bottom Line
cloudflared is off the table for this specific job as of version 2026.2.0. If you already have it running for Tunnels or Zero Trust, that’s unrelated and still fine, but don’t reach for it as a DNS-over-HTTPS forwarder anymore.
Use dnscrypt-proxy if:
- You want to choose your upstream resolver (Quad9, Mullvad, AdGuard, or others)
- Provider independence matters to you: today you trust Cloudflare, tomorrow maybe you don’t
- You want ODoH’s relay-based anonymization
- You like the idea of automatic failover and latency-based load balancing across multiple resolvers
- You’re the type who actually reads config files for fun (we see you)
Honestly, for most homelabs where privacy from your ISP is the goal, dnscrypt-proxy is the better default. It doesn’t require you to place all your trust in a single company, it supports better protocols, and the extra configuration is a one-time cost. cloudflared’s strength is simplicity, but simplicity that comes with permanent lock-in is a trade-off worth being conscious of.
Either way, your ISP is about to have a very boring DNS log.