Debugging DNS Resolution Failures in WireGuard Split-Tunnel Configurations: Fixing Leaked Queries and Enforcing Pi-hole for All Tunnel Traffic
Why I worked on this
I ran into frustrating DNS issues with my WireGuard split-tunnel setup. While basic connectivity worked, I noticed some domains resolved incorrectly or bypassed my Pi-hole entirely. This was happening because certain applications weren’t respecting my VPN’s DNS settings, causing queries to leak to my ISP’s resolvers. I needed a solution that would enforce all tunnel traffic to use my Pi-hole DNS server while maintaining a clean split-tunnel configuration.
My real setup or context
Here’s my actual configuration:
- WireGuard server running on a Proxmox VM
- Client machines: Ubuntu 22.04 desktop, Windows 11 laptop
- DNS: Pi-hole running on a separate container (10.10.0.2) within the same network
- Split-tunnel configuration: Only specific traffic routed through WireGuard
- Systemd-resolved handling DNS on client machines
What worked (and why)
After several iterations, I found these key steps to enforce DNS traffic through my Pi-hole:
- Proper AllowedIPs configuration:
I needed to ensure the Pi-hole’s IP was included in the AllowedIPs for the WireGuard peer configuration:
[Peer] ... AllowedIPs = 10.10.0.0/24, 172.17.0.2/32 # Includes Pi-hole IPThis ensures DNS queries to my Pi-hole are routed through the tunnel.
- WireGuard DNS configuration for systemd:
Instead of using the simple DNS setting in WireGuard config, I used systemd-resolved:
[Interface] ... PostUp = resolvectl dns %i 10.10.0.2 PostDown = resolvectl dns %i --emptyThis properly configures the DNS resolver for the WireGuard interface.
- Firewall rules:
I implemented strict firewall rules on both the server and client:
# On WireGuard server (iptables) iptables -A FORWARD -i wg0 -o eth0 -p udp --dport 53 -j DROPThis blocks any DNS queries not going through the tunnel.
- Validation:
To verify the setup, I used these commands:
$ ip route get 10.10.0.2 $ nslookup example.com 10.10.0.2 $ resolvectl status wg0I also checked my Pi-hole logs to confirm all queries were coming through the tunnel.
What didn’t work
Here are the approaches I tried that failed:
- Simple DNS setting in WireGuard config:
Using just
DNS = 10.10.0.2didn’t work reliably with systemd-resolved. Some applications would still bypass it. - Global DNS changes:
Modifying /etc/resolv.conf directly would get overwritten by systemd-resolved, causing intermittent failures.
- Split DNS without proper routing:
Initially, I had my DNS server IP outside the AllowedIPs range, causing DNS queries to go through my default gateway instead of the tunnel.
Key takeaways
- Always include your DNS server IP in AllowedIPs for the WireGuard peer.
- For systemd systems, use resolvectl in PostUp/PostDown scripts rather than the simple DNS setting.
- Implement firewall rules to block DNS leaks at the server level.
- Verify your configuration with multiple tools (nslookup, resolvectl, Pi-hole logs).
- Be aware that some applications may bypass system DNS settings – consider DNS over HTTPS/TLS if needed.
This setup has worked reliably for me across multiple client machines, ensuring all tunnel traffic respects my Pi-hole DNS configuration while maintaining the performance benefits of a split-tunnel approach.