Tech Expert & Vibe Coder

With 15+ years of experience, I specialize in self-hosting, AI automation, and Vibe Coding – building applications using AI-powered tools like Google Antigravity, Dyad, and Cline. From homelabs to enterprise solutions.

debugging dns resolution failures in wireguard split-tunnel configurations: fixing leaked queries and enforcing pi-hole for all tunnel traffic

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:

  1. 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 IP
        

    This ensures DNS queries to my Pi-hole are routed through the tunnel.

  2. 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 --empty
        

    This properly configures the DNS resolver for the WireGuard interface.

  3. 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 DROP
        

    This blocks any DNS queries not going through the tunnel.

  4. 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 wg0
        

    I 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:

  1. Simple DNS setting in WireGuard config:

    Using just DNS = 10.10.0.2 didn’t work reliably with systemd-resolved. Some applications would still bypass it.

  2. Global DNS changes:

    Modifying /etc/resolv.conf directly would get overwritten by systemd-resolved, causing intermittent failures.

  3. 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

  1. Always include your DNS server IP in AllowedIPs for the WireGuard peer.
  2. For systemd systems, use resolvectl in PostUp/PostDown scripts rather than the simple DNS setting.
  3. Implement firewall rules to block DNS leaks at the server level.
  4. Verify your configuration with multiple tools (nslookup, resolvectl, Pi-hole logs).
  5. 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.

Leave a Comment

Your email address will not be published. Required fields are marked *