[SOLVED] Wireguard not connecting to Docker Pi-hole as DNS when WG server is the host for the Docker container

Huzzah, I fixed it! I'll post the solution here because I haven't seen any guides on solving this exact problem, so hopefully this will help anyone else out there who runs into the same thing. Skip to the bottom if you are less interested in the why and how and just want to fix the damn thing :grinning:

The main problem is that with the default WireGuard setup, all traffic is directed to the host's main network interface, so you cannot reach the PiHole docker container. To solve this, you need to be able to route PiHole traffic from WG to the docker bridge interface. While attempting to do this, I ran into several problems:

  1. I was getting the bridge network interface name from ifconfig but it turns out the full interface name is cut off. So I first ran ifconfig so I could see what interface was using 192.168.100.1/30 and found docker-b3. I then ran ip link show | grep docker-b to find the full interface name, which looked something like docker-b3xxxxxx.
  2. The normal PostUp config for Wireguard is iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE. I thought by copying the third iptables command and changing the outbound interface to the bridge interface, I would get traffic flowing through the bridge. My new PostUp config was iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; iptables -t nat -A POSTROUTING -o docker-b3xxxxxx -j MASQUERADE (PostDown is the exact same with -A getting replaced with -D). The problem with this solution is that iptables doesn't know how to selectively forward what traffic where.

The final solution requires ensuring that traffic to 192.168.100.1/30 gets forwarded to the docker bridge, and all traffic but 192.168.100.1/30 goes to the main network interface. This can be achieved by using the -d flag on iptables, and taking advantage of the inversion flag (!). For the iptables command for the main network interface, ! -d 192.168.100.1/30 needs to be added so that all traffic but traffic to 192.168.100.1/30 goes through it. For the iptables command for the bridge interface, add -d 192.168.100.1/30 to tell iptables to send that traffic through that interface.

My final set of PostUp and PostDown rules (additions to the default rules bolded):

PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o docker-b3xxxxxx -d 192.168.100.1/30 -j MASQUERADE; iptables -t nat -A POSTROUTING -o eth0 ! -d 192.168.100.1/30 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o docker-b3xxxxxx -d 192.168.100.1/30 -j MASQUERADE; iptables -t nat -D POSTROUTING -o eth0 ! -d 192.168.100.1/30 -j MASQUERADE

Beefyfish thanks for responding to me, I was working my way towards this solution but your comment helped me realize that there was something off about my initial attempt to fix this.