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

First of all Beefyfish thanks for putting this (Setup on Synology Docker) guide together! I was finally able to migrate Pihole from my Pi Zero to my NAS. I don't know why but my Pi Zero would lock up randomly and become totally unresponsive until I did a hard reboot. It was annoying because it would take down my network due to the lack of a DNS server and forced me to set up another DNS server as a backup which occasionally caused ads to be allowed through.

Anyway, I also run WireGuard on my NAS and haven't had to use it recently due to Coronavirus, however today I finally had to use it and I'm running into issues with reaching the PiHole when I am connected (to be clear I am running WG on a laptop to connect to WG on my NAS). I can neither ping the macvlan IP (192.168.0.6) or the bridge IP (192.168.100.2) of the Pihole container, so running DNS through PiHole via WireGuard is effectively not working. The weird thing is that I can ping the bridge IP of the NAS (192.168.100.1), so it's not a lack of access to the 192.168.100.0/30 subnet. I also double-checked that the NAS can still talk to the bridge IP (192.168.100.2). Anyone have an idea why that could be the case?

EDIT: Just realized that maybe I need to add an iptables rule in the PostUp/PostDown rules to allow IP masquerading on the bridge network (I hope the interface name stays static). I have done that but still don't have connectivity to 192.168.100.2

Is wire guard a docker image on the synology? If so it will talk to the bridge network at ip 192.168.100.1 as that is where the synology resides. Think of the bridge network at a tunnel from pihole and the synology only. You would install wireguard on the host network of the synology (as long as there are no port conflicts).

No it’s installed directly on the NAS as an SPK. Its effectively using the same network as the NAS itself, which led me to think it would use the bridge network. But the IP of PiHole on the bridge network is 192.168.100.2 right? Still can’t reach it. I tried switching to 192.168.100.1 just to check and was unable to get DNS to resolve

I think the problem is that even though I have added a line to PostUp to setup iptables for the bridged network interface, WireGuard is always going through the primary interface (eth0) for all requests. I probably need to selectively route 192.168.100.1/30 traffic through the bridged network interface but I’m unclear how to do that. Will have to keep googling because iptables is a mystery to me

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.

Just to be safe I would do a full reboot of the synology. Sometimes iptables do not like to stick on the synologys. You may need to write a script to add the iptable settings on boot of the unit.

I would hate for the power to force reboot and whomever is using the internet freak out.

Thanks, I already did a reboot and have a shutdown and startup task that respectively disables and enables the WireGuard interface, and as part that they build up and tear down the iptables rules. This has been stably working for a while now so the additional rule shouldn't be a problem.

From what I'm reading here you weren't running Pi-hole in --net="host" mode, can you confirm?

I've been trying to get it to work for serveral hours now without succes. I am running Pi-hole in --net="host" mode as suggested in Docker DHCP and Network Modes - Pi-hole documentation.

Thanks in advance!

That's correct. Synology wants port 80 and 443 to itself so you can't put it on the host network. You could expose different ports (8080 and 8443 as an example) without much extra work, but then you won't be able to route your Synology traffic through it. To do that, I had to follow the instructions on setting up a macvlan for pihole (linked in the original post)