Why Encrypt Your DNS Traffic?
Every time you visit a website, your device performs a DNS lookup to translate the domain name into an IP address. By default, these lookups travel in plain text — anyone on your network (your ISP, a coffee shop Wi-Fi operator, or a malicious actor) can see every site you visit, block access to specific domains, or even redirect you to fraudulent sites through DNS spoofing.
Encrypting DNS traffic solves all three problems:
- Privacy: Your ISP and network observers can no longer see which domains you’re looking up. They only see encrypted connections to your DNS resolver.
- Integrity: DNS-over-HTTPS (DoH), DNS-over-TLS (DoT), and DNSCrypt use cryptographic verification to ensure responses haven’t been tampered with in transit.
- Censorship resistance: Encrypted DNS bypasses many forms of DNS-based blocking and filtering, giving you control over which resolver you trust.
Self-hosting your own encrypted DNS proxy gives you the best of both worlds: you pick the upstream resolvers you trust, you control the caching and filtering behavior, and every device on your network benefits from encrypted lookups without needing individual configuration.
Three Protocols, Three Tools
Three protocols dominate encrypted DNS, each with a leading open-source implementation:
| Protocol | How It Works | Leading Tool | Port |
|---|---|---|---|
| DNS-over-HTTPS (DoH) | DNS queries wrapped in HTTPS requests | cloudflared | 443 |
| DNS-over-TLS (DoT) | DNS queries over a dedicated TLS connection | stubby | 853 |
| DNSCrypt v2 | DNS queries encrypted with NaCl cryptography | dnscrypt-proxy | 443 |
DNS-over-HTTPS (DoH)
DoH sends DNS queries as standard HTTPS requests to a resolver endpoint. The biggest advantage is that DoH traffic is indistinguishable from regular HTTPS — firewalls and deep packet inspection systems cannot tell it apart from browsing a website. Cloudflare, Google, and Quad9 all operate public DoH resolvers.
DNS-over-TLS (DoT)
DoT uses a dedicated port (853) with TLS encryption. It’s simpler to implement than DoH since it doesn’t need to speak HTTP, but the dedicated port makes it easy for network administrators to block. Most modern operating systems support DoT natively.
DNSCrypt v2
DNSCrypt is a protocol designed specifically for DNS encryption. Unlike DoH and DoT, DNSCrypt provides authenticated encryption — you cryptographically verify the identity of the resolver, not just the transport. The dnscrypt-proxy tool supports multiple resolvers, automatic fallback, and built-in filtering.
Setting Up cloudflared (DoH)
Cloudflared is Cloudflare’s official DoH proxy. It listens on a local port, forwards queries to Cloudflare’s DoH endpoint over HTTPS, and caches responses.
docker Compose Setup
Create a directory for your DoH proxy:
| |
Create docker-compose.yml:
| |
Start the service:
| |
Verify it’s working:
| |
You should see an IP address returned. To confirm encryption is working, check the metrics endpoint:
| |
Multiple Upstream Resolvers
For resilience, configure multiple upstream DoH providers. cloudflared will query all configured resolvers and use the fastest response:
| |
Making It System-Wide
Configure your system to use the local proxy as its DNS resolver. Edit /etc/systemd/resolved.conf:
| |
Then restart the resolver:
| |
Setting Up stubby (DoT)
Stubby is developed by the GetDNS project and is the reference implementation for DNS-over-TLS. It’s lightweight, supports strict TLS verification, and can round-robin across multiple upstream resolvers.
Docker Compose Setup
Create the configuration directory:
| |
Create stubby.yml — the main configuration file:
| |
Key configuration notes:
round_robin_upstreams: 1distributes queries evenly across resolvers for load balancingtls_query_padding_blocksize: 128pads queries to obscure their exact size, adding a layer of privacytls_auth_nameensures the TLS certificate matches the expected hostname, preventing man-in-the-middle attacks
Create docker-compose.yml:
| |
Start and test:
| |
Verifying TLS Is Active
To confirm queries are actually encrypted, use stubby’s built-in status check:
| |
You should see lines confirming TLS handshakes with your configured upstream servers.
Setting Up dnscrypt-proxy
dnscrypt-proxy is the most feature-rich option. It supports DNSCrypt v2, DoH, and DoT simultaneously, with built-in caching, load balancing, filtering, and cloaking.
Docker Compose Setup
| |
Create dnscrypt-proxy.toml:
| |
Create docker-compose.yml:
| |
Start and test:
| |
Using the Built-in Blocklist
One of dnscrypt-proxy’s strongest features is its built-in ad and malware blocking. Add this to your configuration:
| |
This automatically downloads and maintains blocklists from OISD (one of the best community-maintained blocklists) and a malware domain list, refreshing every 72 hours.
Comparison: Which Tool Should You Use?
| Feature | cloudflared | stubby | dnscrypt-proxy |
|---|---|---|---|
| Protocols | DoH only | DoT only | DNSCrypt v2, DoH, DoT |
| Ease of Setup | Easiest | Easy | Moderate |
| Multiple Upstreams | Yes (fastest wins) | Yes (round-robin) | Yes (LB + fallback) |
| Built-in Caching | Basic | No (relies on system) | Advanced (TTL control) |
| Ad Blocking | No | No | Yes (blocklist support) |
| Cloaking | No | No | Yes |
| IPv6 | Yes | Yes | Yes |
| Query Logging | Metrics only | Logs | Full query/NX logs |
| Binary Size | ~30 MB | ~2 MB | ~8 MB |
| Memory Usage | ~40 MB | ~5 MB | ~15 MB |
| Best For | Quick DoH setup | Minimal DoT | Full-featured proxy |
Quick Decision Guide
Choose cloudflared if you want the simplest possible DoH setup and already trust Cloudflare’s infrastructure. It’s essentially a “set and forget” solution.
Choose stubby if you want a minimal, purpose-built DoT proxy with the smallest footprint. It’s ideal for resource-constrained environments like a Raspberry Pi running alongside other services.
Choose dnscrypt-proxy if you want the most features — protocol flexibility, caching, ad blocking, cloaking, and detailed logging. It’s the Swiss Army knife of encrypted DNS.
Integrating with Pi-hole or adguard home
The most powerful setup combines encrypted DNS upstream with a local DNS filter. Here’s how to chain them together.
With Pi-hole
Edit /etc/pihole/setupVars.conf and set the upstream DNS to your encrypted proxy:
| |
Then restart Pi-hole:
| |
In this chain: Pi-hole handles ad blocking and local DNS → forwards to dnscrypt-proxy/cloudflared → which encrypts the query to the upstream resolver.
With AdGuard Home
In the AdGuard Home web interface, go to Settings → DNS Settings and set your upstream servers:
| |
Or edit AdGuardHome.yaml directly:
| |
This gives you the full stack: client → AdGuard Home (filtering) → encrypted proxy (DoH/DoT/DNSCrypt) → upstream resolver.
With a Single Docker Compose
You can run the entire stack in one compose file:
| |
Configure AdGuard Home’s upstream to dnscrypt-proxy:5400 using Docker’s internal DNS resolution.
Choosing Trustworthy Upstream Resolvers
Encryption protects your queries in transit, but the upstream resolver can still see them. Choose resolvers based on their privacy policies:
| Resolver | Protocol | No-Log Policy | Location |
|---|---|---|---|
| Cloudflare (1.1.1.1) | DoH, DoT | Yes (audited by KPMG) | Global |
| Quad9 (9.9.9.9) | DoH, DoT, DNSCrypt | Yes | Switzerland |
| Google (8.8.8.8) | DoH, DoT | Limited logging | Global |
| DNS.SB | DoH, DoT | Yes | Iceland |
| NextDNS | DoH, DoT | Configurable | Global (customizable) |
| Mullvad DNS | DoH, DoT | Yes | Sweden |
For maximum privacy, use a combination of Quad9 (Swiss jurisdiction, strong privacy) and Mullvad (no-account DNS with no persistent logs).
Common Pitfalls and Troubleshooting
DNS Resolution Fails After Switching
If your system can’t resolve domains after pointing to the local proxy, check:
| |
A common issue is systemd-resolved still pointing to the old DNS servers. Fix it with:
| |
Slow Resolution Times
If queries feel slow, the issue is usually one of:
- No local caching — stubby has no built-in cache. Pair it with
unboundor switch to dnscrypt-proxy which caches by default. - Geographic distance to upstream — pick resolvers with points of presence near you. Use
digto measure latency:1 2dig @1.1.1.1 example.com | grep "Query time" dig @9.9.9.9 example.com | grep "Query time" - IPv6 fallback delays — if IPv6 is configured but not working, disable it in your proxy config.
Docker Network Conflicts
If your containers can’t reach upstream resolvers, ensure outbound DNS isn’t blocked by Docker’s default bridge:
| |
Conclusion
Encrypting your DNS traffic is one of the highest-impact privacy improvements you can make with minimal effort. The three tools covered here — cloudflared, stubby, and dnscrypt-proxy — each serve different needs, from the simplest possible setup to a fully-featured encrypted DNS proxy with caching and filtering.
The recommended path for most homelab users is dnscrypt-proxy paired with Pi-hole or AdGuard Home: the filter handles ad blocking and local DNS, while dnscrypt-proxy encrypts all upstream queries and adds an additional layer of blocklist protection on top. Run both in Docker, point your router’s DNS to the filter, and every device on your network gets encrypted DNS without any client-side configuration.
Frequently Asked Questions (FAQ)
Which one should I choose in 2026?
The best choice depends on your specific requirements:
- For beginners: Start with the simplest option that covers your core use case
- For production: Choose the solution with the most active community and documentation
- For teams: Look for collaboration features and user management
- For privacy: Prefer fully open-source, self-hosted options with no telemetry
Refer to the comparison table above for detailed feature breakdowns.
Can I migrate between these tools?
Most tools support data import/export. Always:
- Backup your current data
- Test the migration on a staging environment
- Check official migration guides in the documentation
Are there free versions available?
All tools in this guide offer free, open-source editions. Some also provide paid plans with additional features, priority support, or managed hosting.
How do I get started?
- Review the comparison table to identify your requirements
- Visit the official documentation (links provided above)
- Start with a Docker Compose setup for easy testing
- Join the community forums for troubleshooting