DNS Leak Prevention and Firewall Configuration

It is important to block all outbound DNS traffic on the host except traffic destined to your Pi-hole and Unbound services (whether on host or Docker network). This prevents DNS queries from bypassing your private DNS, avoiding leaks to ISP or external resolvers.

Red Hat-based Distros (RHEL, CentOS, Fedora, Rocky Linux, AlmaLinux, etc.) Using firewalld

# Block all outbound DNS TCP/UDP traffic by default
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="0.0.0.0/0" port port="53" protocol="tcp" reject'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="0.0.0.0/0" port port="53" protocol="udp" reject'

# Allow DNS traffic to local Docker bridge subnet (example here: 172.28.0.0/16)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="172.28.0.0/16" port port="53" protocol="tcp" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="172.28.0.0/16" port port="53" protocol="udp" accept'

# Reload firewall to apply rules
sudo firewall-cmd --reload

Debian/Ubuntu Using ufw

# Deny all outgoing DNS traffic by default
sudo ufw deny out 53/tcp
sudo ufw deny out 53/udp

# Allow DNS queries only to Docker network IP range (example: 172.28.0.0/16)
sudo ufw allow out to 172.28.0.0/16 port 53 proto tcp
sudo ufw allow out to 172.28.0.0/16 port 53 proto udp

# Reload ufw to apply changes
sudo ufw reload

Arch Linux or Other Distros Using iptables

# Drop all outbound DNS TCP and UDP traffic
sudo iptables -A OUTPUT -p tcp --dport 53 -j DROP
sudo iptables -A OUTPUT -p udp --dport 53 -j DROP

# Insert rule to ACCEPT DNS traffic to Docker bridge subnet before drop rules
sudo iptables -I OUTPUT -p tcp -d 172.28.0.0/16 --dport 53 -j ACCEPT
sudo iptables -I OUTPUT -p udp -d 172.28.0.0/16 --dport 53 -j ACCEPT

For Arch Linux or Other Distros Using nftables

nft add table inet filter

nft add chain inet filter output { type filter hook output priority 0 \; }

# Drop all outbound DNS traffic
nft add rule inet filter output udp dport 53 drop
nft add rule inet filter output tcp dport 53 drop

# Accept DNS traffic to Docker subnet (replace subnet accordingly)
nft add rule inet filter output ip daddr 172.28.0.0/16 udp dport 53 accept
nft add rule inet filter output ip daddr 172.28.0.0/16 tcp dport 53 accept

Firewall Configuration Notes

  • Replace 172.28.0.0/16 with the actual subnet of your Docker bridge network or host DNS servers as applicable.

  • Ensure all client devices and the host itself use only Pi-hole IP(s) as their DNS servers.

  • Test your DNS leak protection with online tools like dnsleaktest.com.

  • Adjust firewall rules for IPv6 if your network utilizes it.

  • For less common firewalls, consult the distro or firewall documentation for equivalent rules permitting and restricting DNS traffic.

Last updated