DNS over TLS (DoT) with Unbound and Cloudflare
Overview
DNS over TLS (DoT) encrypts DNS queries between your device and the DNS resolver, preventing ISPs and third parties from monitoring or manipulating your DNS traffic. This guide shows how to configure Unbound as a local DNS resolver that forwards queries to Cloudflare's DNS service over TLS.
Why DNS over TLS?
- Privacy: Encrypts DNS queries to prevent eavesdropping and tracking
- Security: Protects against DNS hijacking and man-in-the-middle attacks
- Integrity: Ensures DNS responses haven't been tampered with in transit
- Performance: Cloudflare's 1.1.1.1 service offers fast response times globally
How It Works
Client → Unbound (Local DNS) → TLS Tunnel → Cloudflare DNS (1.1.1.1)
- Clients send DNS queries to Unbound on port 53 (standard DNS)
- Unbound encrypts queries using TLS and forwards to Cloudflare on port 853
- Cloudflare resolves the query and returns encrypted response
- Unbound decrypts and caches the response, then sends to client
Configuration
Unbound config /etc/unbound/unbound.conf.d/my.conf
bash
1server:2 use-syslog: yes3 logfile: "/var/log/unbound.log"4 verbosity: 25 username: "nobody"6 interface: 0.0.0.07 access-control: 0.0.0.0/0 allow8 prefetch: yes9forward-zone:10 name: .11 forward-tls-upstream: yes12 tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"13 forward-addr: 1.1.1.1@853#cloudflare-dns.com14 forward-addr: 1.0.0.1@853#cloudflare-dns.comConfiguration Breakdown
| Parameter | Description | Value |
|---|---|---|
use-syslog | Enable logging to system log | yes |
logfile | Path to Unbound's log file | /var/log/unbound.log |
verbosity | Log detail level (0-5) | 2 (operational info) |
username | User to run Unbound as | nobody (security) |
interface | Network interface to listen on | 0.0.0.0 (all interfaces) |
access-control | Allow/deny clients | 0.0.0.0/0 allow (all networks) |
prefetch | Cache popular queries before expiry | yes (improves performance) |
forward-tls-upstream | Enable TLS for forwarding | yes |
tls-cert-bundle | CA certificates for TLS validation | System CA bundle path |
forward-addr | Upstream DNS server with TLS | IP@PORT#HOSTNAME |
Installation and Setup
Install Unbound
bash
1sudo apt update2sudo apt install unbound -yCreate Configuration
bash
1# Create custom config directory if it doesn't exist2sudo mkdir -p /etc/unbound/unbound.conf.d3
4# Create your custom configuration5sudo nano /etc/unbound/unbound.conf.d/my.confVerify Configuration
bash
1# Test configuration syntax2sudo unbound-checkconf3
4# Expected output:5# unbound-checkconf: no errors in /etc/unbound/unbound.confEnable and Start Service
bash
1# Enable Unbound to start on boot2sudo systemctl enable unbound3
4# Start Unbound service5sudo systemctl start unbound6
7# Check service status8sudo systemctl status unboundTesting DNS over TLS
Test Local DNS Resolution
bash
1# Query localhost (Unbound)2dig @127.0.0.1 example.com3
4# Should return answer section with IP addressVerify TLS Connection
bash
1# Monitor Unbound logs2sudo tail -f /var/log/unbound.log3
4# You should see TLS handshake messages like:5# info: outbound ssl authentication for cloudflare-dns.comTest from Remote Client
bash
1# From another machine on your network2dig @YOUR_SERVER_IP example.com3
4# Test reverse DNS5dig @YOUR_SERVER_IP -x 8.8.8.8Advanced Configuration Examples
Enhanced Security Configuration
bash
1# /etc/unbound/unbound.conf.d/security.conf2server:3 # Harden against attacks4 harden-glue: yes5 harden-dnssec-stripped: yes6 harden-below-nxdomain: yes7 harden-referral-path: yes8 9 # Don't send queries to authoritative servers from private IP ranges10 use-caps-for-id: yes11 12 # Privacy settings13 hide-identity: yes14 hide-version: yes15 16 # Performance tuning17 cache-min-ttl: 30018 cache-max-ttl: 8640019 prefetch-key: yes20 21 # Thread optimization (adjust based on CPU cores)22 num-threads: 423 msg-cache-slabs: 424 rrset-cache-slabs: 425 infra-cache-slabs: 426 key-cache-slabs: 4Network Restriction Configuration
bash
1# /etc/unbound/unbound.conf.d/network.conf2server:3 # Listen only on specific interface4 interface: 192.168.1.105 interface: ::16 7 # Restrict access to local networks only8 access-control: 127.0.0.0/8 allow9 access-control: 192.168.0.0/16 allow10 access-control: 10.0.0.0/8 allow11 access-control: 172.16.0.0/12 allow12 access-control: ::1 allow13 access-control: fc00::/7 allow14 15 # Deny everything else16 access-control: 0.0.0.0/0 refuseMultiple Upstream Providers Configuration
bash
1# /etc/unbound/unbound.conf.d/multi-upstream.conf2forward-zone:3 name: .4 forward-tls-upstream: yes5 tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"6 7 # Cloudflare (Primary)8 forward-addr: 1.1.1.1@853#cloudflare-dns.com9 forward-addr: 1.0.0.1@853#cloudflare-dns.com10 11 # Quad9 (Secondary - Privacy focused)12 forward-addr: 9.9.9.9@853#dns.quad9.net13 forward-addr: 149.112.112.112@853#dns.quad9.netSplit DNS Configuration
bash
1# /etc/unbound/unbound.conf.d/split-dns.conf2# Forward internal domain to local DNS server3forward-zone:4 name: "internal.company.com"5 forward-addr: 192.168.1.16 7# Forward everything else via DoT to Cloudflare8forward-zone:9 name: .10 forward-tls-upstream: yes11 tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"12 forward-addr: 1.1.1.1@853#cloudflare-dns.com13 forward-addr: 1.0.0.1@853#cloudflare-dns.comMonitoring and Troubleshooting
View Real-time Statistics
bash
1# Get Unbound statistics2sudo unbound-control stats_noreset3
4# View cache information5sudo unbound-control dump_cache6
7# Check configuration8sudo unbound-control statusCommon Issues
TLS Handshake Failures
bash
1# Check if CA certificates are installed2ls -la /etc/ssl/certs/ca-certificates.crt3
4# Update CA certificates (Ubuntu/Debian)5sudo update-ca-certificates6
7# Update CA certificates (Fedora/RHEL)8sudo update-ca-trustPort 853 Blocked
bash
1# Test connectivity to Cloudflare DoT2openssl s_client -connect 1.1.1.1:853 -servername cloudflare-dns.com3
4# Should show SSL handshake and certificate infoPerformance Issues
bash
1# Increase cache sizes in configuration2server:3 msg-cache-size: 50m4 rrset-cache-size: 100m5 cache-max-ttl: 864006 cache-min-ttl: 3007 8 # Adjust based on available RAM9 # Formula: rrset-cache-size = 2 * msg-cache-sizeFirewall Configuration
Allow DNS Traffic
bash
1# UFW (Ubuntu)2sudo ufw allow 53/tcp3sudo ufw allow 53/udp4
5# Firewalld (Fedora/RHEL)6sudo firewall-cmd --permanent --add-service=dns7sudo firewall-cmd --reload8
9# iptables10sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT11sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPTAllow Outbound DoT
bash
1# Ensure outbound connections to port 853 are allowed2sudo ufw allow out 853/tcp3
4# Or with iptables5sudo iptables -A OUTPUT -p tcp --dport 853 -j ACCEPTPerformance Benchmarking
Compare DNS Resolver Performance
bash
1# Install dnsperf2sudo apt install dnsperf # Ubuntu/Debian3
4# Create test query file5echo "example.com A" > queries.txt6echo "google.com A" >> queries.txt7echo "github.com A" >> queries.txt8
9# Benchmark local Unbound10dnsperf -s 127.0.0.1 -d queries.txt11
12# Benchmark direct Cloudflare13dnsperf -s 1.1.1.1 -d queries.txtIntegration with System
Configure System to Use Unbound
systemd-resolved (Modern Linux)
bash
1# Edit resolved configuration2sudo nano /etc/systemd/resolved.conf3
4# Set:5[Resolve]6DNS=127.0.0.17FallbackDNS=1.1.1.18DNSStubListener=no9
10# Restart service11sudo systemctl restart systemd-resolved12
13# Update symlink14sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.confTraditional resolv.conf
bash
1# Edit resolv.conf2sudo nano /etc/resolv.conf3
4# Add:5nameserver 127.0.0.16options edns0 trust-adNetworkManager
bash
1# Edit NetworkManager configuration2sudo nano /etc/NetworkManager/NetworkManager.conf3
4# Add:5[main]6dns=none7
8# Restart NetworkManager9sudo systemctl restart NetworkManagerSecurity Considerations
- Access Control: Restrict access to trusted networks only in production
- Logging: Consider privacy implications of DNS query logging
- Updates: Keep Unbound and system packages updated for security patches
- TLS Validation: Always verify TLS certificates to prevent MITM attacks
- Fallback: Configure fallback DNS servers in case of DoT failures
Additional Resources
Alternative DoT Providers
| Provider | Primary IP | Secondary IP | Hostname |
|---|---|---|---|
| Cloudflare | 1.1.1.1 | 1.0.0.1 | cloudflare-dns.com |
| Quad9 | 9.9.9.9 | 149.112.112.112 | dns.quad9.net |
| AdGuard | 94.140.14.14 | 94.140.15.15 | dns.adguard.com |
| CleanBrowsing | 185.228.168.9 | 185.228.169.9 | security-filter-dns.cleanbrowsing.org |