How Unbound Works
When you use Google DNS (8.8.8.8) or Cloudflare (1.1.1.1), your DNS queries pass through their servers — they can see every domain you visit. Unbound cuts out the middleman entirely.
🔒 True DNS privacy — Unbound contacts root servers (like a.root-servers.net) directly, then follows the delegation chain to find the authoritative answer. No third party is involved.
🔗 Best paired with Pi-hole or AdGuard Home — use Unbound as the upstream resolver for Pi-hole/AdGuard to get both ad blocking AND full DNS privacy.
Step-by-Step Installation
Install Unbound
sudo apt update
sudo apt install unbound -y
Download Root Hints
Root hints tell Unbound where the root DNS servers are. These are automatically maintained but it's good practice to fetch a fresh copy:
sudo curl -o /var/lib/unbound/root.hints \
https://www.internic.net/domain/named.root
Configure Unbound
Create a configuration file for Pi-hole/AdGuard integration (listening on port 5335 to avoid conflict with Pi-hole on port 53):
sudo nano /etc/unbound/unbound.conf.d/pi-hole.conf
Paste the following configuration:
server:
# Logging (disable for privacy)
verbosity: 0
# Interface and port
interface: 127.0.0.1
port: 5335
# Allow queries only from localhost
access-control: 127.0.0.1/32 allow
# Root hints file
root-hints: "/var/lib/unbound/root.hints"
# DNSSEC validation
harden-dnssec-stripped: yes
use-caps-for-id: no
# Privacy settings
harden-glue: yes
harden-referral-path: yes
harden-algo-downgrade: no
private-address: 192.168.0.0/16
private-address: 169.254.0.0/16
private-address: 172.16.0.0/12
private-address: 10.0.0.0/8
private-address: fd00::/8
private-address: fe80::/10
# Performance
prefetch: yes
num-threads: 1
so-rcvbuf: 1m
cache-min-ttl: 3600
cache-max-ttl: 86400
neg-cache-size: 4m
# Minimal response size
minimal-responses: yes
val-log-level: 1
Start and Enable Unbound
sudo systemctl enable unbound
sudo systemctl restart unbound
# Check it's running without errors:
sudo systemctl status unbound
Test Unbound is Working
# Test a normal resolution (should return an IP):
dig pi-hole.net @127.0.0.1 -p 5335
# Test DNSSEC validation (should show "ad" flag):
dig sigok.verteiltesysteme.net @127.0.0.1 -p 5335
# Test DNSSEC rejection of bad signatures (should fail/SERVFAIL):
dig sigfail.verteiltesysteme.net @127.0.0.1 -p 5335
✅ If the first two return results and the third returns SERVFAIL — DNSSEC is working correctly.
Point Pi-hole to Unbound
In Pi-hole admin: Settings → DNS. Uncheck all upstream DNS providers, then add a Custom DNS server:
Custom upstream DNS server 1: 127.0.0.1#5335
Click Save. Pi-hole now uses Unbound as its resolver — you have ad blocking AND recursive DNS privacy.
Point AdGuard Home to Unbound (Alternative)
If using AdGuard Home instead of Pi-hole: Settings → DNS Settings → Upstream DNS servers:
127.0.0.1:5335
Useful Commands
| Task | Command |
|---|---|
| Restart Unbound | sudo systemctl restart unbound |
| View status | sudo systemctl status unbound |
| View logs | sudo journalctl -u unbound -f |
| Check config syntax | unbound-checkconf |
| Update root hints | sudo curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.root |
| Cache stats | sudo unbound-control stats_noreset |
| Flush cache | sudo unbound-control flush_zone . |
Architecture Overview
When paired together, your DNS stack looks like this:
📱 Client device → asks Pi-hole/AdGuard for DNS → Pi-hole checks blocklists → if not blocked, forwards to Unbound → Unbound queries root servers → answer returned to device. Every step happens on your local network.