🍓 Pi Zero W2 AdGuard + Unbound Setup

Complete DNS Privacy & DNSSEC Validation Guide

Part 1: Initial Pi Setup

1.1 SSH into the Pi

ssh [email protected]

Or use IP address if .local doesn't work:

ssh username@YOUR_PI_IP_ADDRESS

1.2 Update System

sudo apt update
sudo apt upgrade -y

1.3 Install Required Tools

⚠️ IMPORTANT: These tools are required for testing and don't come pre-installed on Raspberry Pi OS

sudo apt install -y curl wget nano dnsutils tcpdump
  • curl - Download files
  • wget - Download files
  • nano - Text editor
  • dnsutils - Contains dig command (REQUIRED for testing DNS)
  • tcpdump - Network traffic analyzer (REQUIRED for verifying no ISP leaks)

Part 2: Install Unbound

2.1 Install Unbound

sudo apt install -y unbound

2.2 Create Unbound Configuration

sudo nano /etc/unbound/unbound.conf.d/recursive.conf

⚠️ IMPORTANT: Copy this entire configuration exactly and paste into the editor:

server:
    interface: 0.0.0.0
    port: 5335
    do-ip4: yes
    do-ip6: no
    do-udp: yes
    do-tcp: yes
    num-threads: 2
    qname-minimisation: yes
    val-permissive-mode: no
    aggressive-nsec: yes
    hide-identity: yes
    hide-version: yes
    harden-glue: yes
    harden-dnssec-stripped: yes
    use-caps-for-id: yes
    tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"
    cache-min-ttl: 300
    cache-max-ttl: 14400
    msg-cache-size: 128m
    rrset-cache-size: 256m
    access-control: 127.0.0.1/32 allow
    access-control: 192.168.0.0/16 allow
    access-control: 172.16.0.0/12 allow
    access-control: 10.0.0.0/8 allow

Save with: Ctrl+X, then Y, then Enter

2.3 Verify & Start Unbound

sudo unbound-checkconf

Should show: "unbound-checkconf: no errors in /etc/unbound/unbound.conf"

sudo systemctl enable unbound
sudo systemctl restart unbound
sudo systemctl status unbound

2.4 Verify Unbound is Listening

sudo ss -tlnp | grep 5335

Should show: "LISTEN 0 256 0.0.0.0:5335"

2.5 Test Unbound

dig @127.0.0.1 -p 5335 google.com
dig @127.0.0.1 -p 5335 dnssec.works +dnssec

Second query should show: "flags: qr rd ra ad;" (ad = DNSSEC validated)

Part 3: Install AdGuard Home

3.1 Download and Install

cd /opt
sudo curl -L https://static.adguard.com/adguardhome/release/AdGuardHome_linux_arm64.tar.gz -o AdGuardHome.tar.gz
sudo tar -xzf AdGuardHome.tar.gz
cd AdGuardHome
sudo ./AdGuardHome -s install

3.2 Start AdGuard

sudo systemctl start AdGuardHome
sudo systemctl enable AdGuardHome

3.3 Access Web Interface

Open browser: http://YOUR_PI_IP_ADDRESS:3000

Complete the setup wizard and create admin account.

Part 4: Configure AdGuard to Use Unbound

4.1 Set Upstream DNS

  • Go to http://YOUR_PI_IP_ADDRESS:3000
  • Click SettingsDNS Settings
  • In Upstream DNS servers, enter: 127.0.0.1:5335
  • Click Save

4.2 Disable AdGuard's DNSSEC

  • In DNS Settings, find DNSSEC protection
  • Turn it OFF (uncheck)
  • Click Save

Part 5: Configure Router DNS

5.1 Router Configuration (Recommended)

  • Access router admin panel (usually 192.168.1.1)
  • Go to DHCP Settings or DNS Settings
  • Set Primary DNS to: YOUR_PI_IP_ADDRESS
  • Leave Secondary DNS blank
  • Save and restart router

Now all devices automatically use AdGuard!

5.2 Manual Configuration (Alternative)

On Linux:

sudo nano /etc/resolv.conf

Change to:

nameserver YOUR_PI_IP_ADDRESS

Part 6: Test Your Setup

6.1 Test from Laptop

dig @YOUR_PI_IP_ADDRESS google.com
dig @YOUR_PI_IP_ADDRESS dnssec.works +dnssec

Second query should show "ad" flag

6.2 Test Recursive Resolution

dig @YOUR_PI_IP_ADDRESS example.com +trace

Should show root nameservers being queried

6.3 Verify No ISP DNS Leaks

sudo tcpdump -i any -n 'udp port 53' | head -20

Run DNS query in another terminal. Should see YOUR_PI_IP_ADDRESS, NOT ISP servers.

6.4 Check AdGuard Query Log

  • Go to http://YOUR_PI_IP_ADDRESS:3000
  • Click Query Log
  • Should see your DNS queries with status OK

Part 7: Verify DNSSEC

7.1 Test Valid DNSSEC

dig @YOUR_PI_IP_ADDRESS dnssec.works +dnssec

Should show: status NOERROR, flags with "ad", RRSIG record

7.2 Test Invalid DNSSEC

dig @YOUR_PI_IP_ADDRESS dnssec-failed.org +dnssec

Should show: status SERVFAIL (correctly rejected bad signature)

7.3 Online Tests

Visit these sites to verify:

Part 8: Optional - Add DoT (DNS over TLS)

8.1 Update Unbound Config

sudo nano /etc/unbound/unbound.conf.d/recursive.conf

Add this section at the end:

forward-zone:
    name: "."
    forward-tls-upstream: yes
    forward-addr: 1.1.1.1@853#cloudflare-dns.com
    forward-addr: 1.0.0.1@853#cloudflare-dns.com

8.2 Restart Unbound

sudo systemctl restart unbound

8.3 Test DoT

dig @YOUR_PI_IP_ADDRESS dnssec.works +dnssec

Should still show "ad" flag. Query time may be 200-400ms (normal for DoT)

Troubleshooting

Issue: AdGuard cannot reach Unbound

Error: "could not be used"

Solution: Check access control in Unbound

sudo nano /etc/unbound/unbound.conf.d/recursive.conf

Verify this line exists:

access-control: 192.168.0.0/16 allow

Then restart:

sudo systemctl restart unbound

Issue: DNSSEC queries show SERVFAIL

Solution: Check certificate bundle

ls -lh /etc/ssl/certs/ca-certificates.crt

If missing, reinstall:

sudo apt install --reinstall ca-certificates
sudo update-ca-certificates
sudo systemctl restart unbound

Issue: DNS is slow

Solution: Increase cache size

sudo nano /etc/unbound/unbound.conf.d/recursive.conf

Change:

msg-cache-size: 256m
rrset-cache-size: 512m

Restart:

sudo systemctl restart unbound

Final Verification Checklist

  • Unbound listening on port 5335
  • AdGuard listening on port 53
  • DNSSEC validation working (ad flag present)
  • Root server queries visible
  • No ISP DNS leaks
  • cmdns score 85%+
  • All devices using Pi's DNS