Every domain you resolve goes through a DNS resolver. By default, that's Google (8.8.8.8), Cloudflare (1.1.1.1), or your ISP (all of which log your queries). Your browsing history is essentially visible to them.
Ultimate DNS Shield breaks that dependency entirely. Unbound resolves domains by querying root nameservers directly. Pi-hole drops ad and tracker domains before they reach the network stack. No third-party resolver ever sees your queries.
This is not about hiding from law enforcement; it's about reducing unnecessary data exposure to commercial entities and your ISP.
Architecture
Three layers, all containerised on an isolated Docker bridge network (dns-net). Unbound is never exposed to the LAN (only Pi-hole can reach it).
LAN devices ──► Pi-hole :53 (172.20.0.3)
│
└──► Unbound :5335 (172.20.0.2) (internal only)
│
└──► Root nameservers (a-m.root-servers.net)
networks:
dns-net:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
services:
unbound:
image: mvance/unbound:latest
networks:
dns-net:
ipv4_address: 172.20.0.2
pihole:
image: pihole/pihole:latest
networks:
dns-net:
ipv4_address: 172.20.0.3
ports:
- "53:53/tcp"
- "53:53/udp"
- "80:80/tcp"
Pi-hole forwards unblocked queries to Unbound via PIHOLE_DNS_=172.20.0.2#5335 (not a public resolver).
Prerequisites
- Raspberry Pi 4 (2 GB RAM minimum)
- Raspberry Pi OS Lite 64-bit
- Static LAN IP on the Pi
- Docker + Docker Compose installed
- Port 53 free on the host
Watch out:
systemd-resolvedoccupies port 53 by default on Ubuntu/Pi OS. Disable it first:sudo systemctl disable --now systemd-resolved
Installation
git clone https://github.com/cherifon/Ultimate-DNS-Shield.git
cd Ultimate-DNS-Shield
Edit config/docker-compose.yml:
environment:
TZ: Europe/Paris
WEBPASSWORD: your_password
volumes:
- /home/pi/pihole:/etc/pihole
- /home/pi/dnsmasq:/etc/dnsmasq.d
# Preview (no changes applied)
sudo bash scripts/install.sh --dry-run
# Full install
sudo bash scripts/install.sh
Point your router's DHCP DNS to the Pi's LAN IP (every device is covered automatically).
Security hardening
sudo bash scripts/security.sh
- UFW (port 53 and 80 from LAN only; everything else denied)
- Fail2Ban (rate-limits DNS floods and web UI brute-force)
- DNSSEC (enforced in Unbound; invalid signatures rejected)
-
Unbound isolation (bound to
172.20.0.2only; unreachable from outside Docker's bridge)
Verification
# Normal resolution (answered by your Pi)
dig github.com @<PI_IP>
# Ad blocking (returns 0.0.0.0)
dig doubleclick.net @<PI_IP>
# DNSSEC (invalid signature correctly rejected)
dig sigfail.verteiltesysteme.net @<PI_IP>
Results
- No DNS query resolved by a third party
- Ad and tracker domains blocked network-wide
- DNSSEC enforced
- First-query latency ~8ms on LAN; cached queries <1ms
- Full stack managed via two scripts
GitHub: cherifon/Ultimate-DNS-Shield
Originally published on cherifjebali.com
Top comments (0)