Why I Needed to Fix This
I run Pi-hole on my home network for ad blocking and local DNS resolution. I also use Tailscale to access my home network remotely. Both systems wanted to handle DNS for my internal domain names, and they kept stepping on each other.
The problem showed up when I tried to access services like proxmox.home or synology.home. From my laptop at home, Pi-hole would resolve these correctly to local IPs. But when I connected through Tailscale from outside, MagicDNS would try to resolve them first and fail, because it didn't know about my local network.
I needed the same domain name to resolve differently depending on where I was connecting from—local IPs when at home, Tailscale IPs when remote.
My Setup
Pi-hole runs in a Docker container on my Proxmox host. I use it as the primary DNS server for my home network, configured in my router's DHCP settings.
Tailscale is installed on several devices—my laptop, phone, and the Proxmox host itself. I enabled MagicDNS in the Tailscale admin console because it's convenient for accessing devices by name over the VPN.
The conflict happened because:
- Pi-hole had custom DNS records for my internal services pointing to
192.168.x.xaddresses - Tailscale MagicDNS wanted to resolve those same names to
100.x.x.xTailscale IPs - Both systems were trying to be authoritative for my
.homedomain
What Didn't Work
I initially tried to use Tailscale's split DNS feature to forward queries for my .home domain to Pi-hole's IP address. The idea was that Tailscale would handle routing the query to Pi-hole, which would then return the correct answer.
This failed because Pi-hole saw all queries coming from Tailscale's internal network interface, not from the original client. It couldn't distinguish between a query from my laptop at home versus my phone connected remotely.
I also tried running Pi-hole in Docker's bridge network mode, thinking I could isolate the DNS traffic. Same problem—all queries appeared to come from Docker's internal subnet, making source-based routing impossible.
I looked at conditional forwarding in Pi-hole's settings, but that's designed for reverse lookups (IP to hostname), not for splitting forward lookups based on the client's location.
What Actually Worked
The solution required two changes:
1. Run Pi-hole in Docker Host Network Mode
I changed my Pi-hole Docker configuration to use network_mode: host. This made Pi-hole see the actual source IP of every DNS query, not Docker's internal gateway.
My docker-compose.yml excerpt:
services:
pihole:
image: pihole/pihole:latest
network_mode: host
environment:
TZ: 'America/New_York'
WEBPASSWORD: 'mypassword'
volumes:
- './etc-pihole:/etc/pihole'
- './etc-dnsmasq.d:/etc/dnsmasq.d'
This broke port mapping syntax, but since Pi-hole was now directly on the host network, it didn't matter—it listened on the host's actual interfaces.
2. Configure dnsmasq for Split-Horizon DNS
Pi-hole uses dnsmasq under the hood. I created a custom dnsmasq configuration file to return different IPs based on which network interface received the query.
I added this to /etc/dnsmasq.d/02-split-dns.conf inside the Pi-hole container:
localise-queries host-record=proxmox.home,192.168.1.50 host-record=proxmox.home,100.64.1.50 host-record=synology.home,192.168.1.60 host-record=synology.home,100.64.1.60
The localise-queries directive tells dnsmasq to return the IP that matches the source network. If a query comes from a device on 192.168.1.x, it returns the 192.168.1.x address. If it comes from Tailscale's 100.64.x.x subnet, it returns the Tailscale IP.
I restarted the Pi-hole container, and suddenly everything worked. My laptop at home got local IPs. My phone over Tailscale got Tailscale IPs. Same domain names, different answers.
One Remaining Issue
This setup only works if the querying device is on the same subnet as one of the configured IPs. If I'm on a completely different network (like a coffee shop WiFi), dnsmasq doesn't know which IP to return and picks one arbitrarily.
In practice, this hasn't been a problem because I'm either at home (local network) or using Tailscale (Tailscale network). But it's worth knowing the limitation exists.
Key Takeaways
Docker's bridge networking hides the real source IP of DNS queries. If you need source-based DNS routing, use host network mode.
Split-horizon DNS is built into dnsmasq—you don't need separate Pi-hole instances or complex forwarding rules. You just need the right dnsmasq directives.
Tailscale's split DNS feature is useful for forwarding entire domains to a specific nameserver, but it doesn't solve the problem of returning different IPs based on client location. That requires source-aware DNS resolution on the server side.
Testing this required patience. I had to clear DNS caches on every device, wait for TTLs to expire, and verify queries with dig from different networks to confirm it was actually working.
The setup has been stable for months now. I don't think about it anymore, which is exactly how infrastructure should feel when it's working correctly.