How to Set Up Pi-hole v6 with Unbound on Raspberry Pi Using Docker
· Travis Rodgers · 3 min read
Pi-hole is a powerful network-wide ad blocker that runs on your local network. Pairing it with Unbound—a recursive DNS resolver—gives you complete control over DNS queries without relying on third-party DNS providers like Google or Cloudflare.
This guide shows you how to deploy Pi-hole v6 (which is very much different from v5) with Unbound on a Raspberry Pi using Docker Compose.
Prerequisites
Raspberry Pi (3, 4, or 5) running Ubuntu Server LTS with Docker/Docker Compose installed.
Step 1: Disable systemd-resolved
Pi-hole needs port 53, which is used by systemd-resolved by default:
sudo systemctl disable systemd-resolved
sudo systemctl stop systemd-resolvedStep 2: Create Directory Structure
It’s good practice to deploy applications in the /srv folder (on your Pi).
mkdir -p /srv/docker/pihole/unbound
cd /srv/docker/piholeStep 3: Create Unbound Configuration
Create /srv/docker/pihole/unbound/unbound.conf:
server:
# Port to listen on (non-standard to avoid conflict with Pi-hole)
port: 5335
# Listen on all interfaces (accessible within shared network namespace)
interface: 0.0.0.0
# Use IPv4 only
do-ip4: yes
do-ip6: no
do-udp: yes
do-tcp: yes
# Trust glue only if it is within the servers authority
harden-glue: yes
# Require DNSSEC data for trust-anchored zones
harden-dnssec-stripped: yes
# Don't use Capitalization randomization
use-caps-for-id: no
# Reduce EDNS reassembly buffer size
edns-buffer-size: 1232
# Perform prefetching of close to expired message cache entries
prefetch: yes
# Number of threads to create
num-threads: 1
# Power of 2 close to num-threads
so-rcvbuf: 1m
# Ensure privacy of local IP ranges
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::/10These values ☝️, if you’re wondering where they came from, are straight from the docs.
Step 4: Create Docker Compose File
Create /srv/docker/pihole/docker-compose.yml:
services:
pihole:
image: pihole/pihole:2025.11.1
container_name: pihole
restart: unless-stopped
# Use host networking for DNS (port 53)
network_mode: host
environment:
- TZ=America/New_York
- FTLCONF_webserver_api_password=changeme123
# - FTLCONF_webserver_domain=pihole.yourdomain.com -- If you plan to have a custom domain for the web interface
- FTLCONF_LOCAL_IPV4=192.168.1.92 # change me
- FTLCONF_dns_upstreams=127.0.0.1#5335;127.0.0.1#5335
volumes:
- ./etc-pihole:/etc/pihole
- ./etc-dnsmasq.d:/etc/dnsmasq.d
cap_add:
- NET_ADMIN
unbound:
image: alpinelinux/unbound:latest
container_name: unbound
restart: unless-stopped
# Share Pi-hole's network stack
network_mode: service:pihole
volumes:
- ./unbound/unbound.conf:/etc/unbound/unbound.conf:roImportant: Update these values:
TZ: Your timezone (list here)FTLCONF_webserver_api_password: Your desired admin passwordFTLCONF_LOCAL_IPV4: Your Raspberry Pi’s static IP address
Step 5: Deploy the Stack
cd /srv/docker/pihole
sudo docker compose up -dStep 6: Verify Unbound Integration
Check that Pi-hole is forwarding queries to Unbound:
# Query a domain
dig google.com @127.0.0.1
# Watch live query log
sudo docker exec pihole pihole -tYou should see queries being forwarded to 127.0.0.1#5335 (Unbound) in the logs.
Step 7: Configure Your Network
Point your router’s DNS settings to your Pi’s IP address (e.g., 192.168.1.92), or configure individual devices to use it as their DNS server.
Key Configuration Notes
Pi-hole v6 Environment Variables
Pi-hole v6 uses FTLCONF_* environment variables instead of the old v5 variables:
- ❌
PIHOLE_DNS_(deprecated) - ✅
FTLCONF_dns_upstreams(use this)
Network Mode
We use network_mode: host for Pi-hole so it can bind to port 53, and network_mode: service:pihole for Unbound so it shares Pi-hole’s network namespace. This allows them to communicate via 127.0.0.1.
Persistent Data
Your Pi-hole configuration is stored in ./etc-pihole, which persists across container restarts and updates.
Troubleshooting
DNS Not Working
Verify systemd-resolved is disabled:
sudo systemctl status systemd-resolvedUnbound Not Connecting
Check if Unbound is running:
sudo docker logs unboundWeb Interface Not Accessible
Access Pi-hole’s web interface at http://YOUR_PI_IP/admin (e.g., http://192.168.1.92/admin)
Updating
To update Pi-hole and Unbound:
cd /srv/docker/pihole
sudo docker compose pull
sudo docker compose up -dYour configuration and data will persist across updates.
Conclusion
You now have a privacy-focused, ad-blocking DNS server running on your Raspberry Pi. All DNS queries are resolved recursively via Unbound without relying on third-party DNS providers, giving you complete control and privacy over your network’s DNS traffic.
This page may contain affiliate links. Please see my affiliate disclaimer for more info.
