Wireguard not using PiHole DNS

I'm at a complete loss... No matter what I do, I cannot get wireguard to use PiHole's DNS.
original reddit post here
Updated configs below:

Symptoms:

  • When connecting to wireguard, I can access my internal services using IP address directly, but domain names are not resolved from the PiHole DNS.

  • PiHole DNS works under normal conditions (inside the LAN; not connected to the VPN).

  • Wireguard works, in that I am connected to my remote machine and my IP shows it's coming from there. I can browse the web no problem, access my internal services using IP addresses, but not the domain name.

Interesting symptom

  • When connected with wireguard, and running $ drill 1.1.1.1 on the client machine, I get Error: error sending query: Could not send or receive, because of network error

    However, I'm still able to resolve webpages in my browser, like https://reddit.com.
    The same occurs for using $ drill <containerIp or hostDnsIp>.

  • PiHole DNS also doesn't work with openvpn

Set up:

  • Wireguard and Pi-Hole running on the same host in docker. The host is a Proxmox Debian VM

  • IP address of the host VM (that hosts both PiHole and Wireguard): 10.0.0.18

  • Firewall is disabled

  • Host's /etc/systctl.conf:

...
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
...
  • Both are connected on the same docker network (also tried in separate docker network)
        "Containers": {
            "1e7ce2595480c3d74ab97268f1a6ef106846a7b4614bca567bcb8f50450074f4": {
                "Name": "pihole",
                "EndpointID": "d5309387e70e8869530fcc3a05b49d10937a507b8b64db242b8041c94b63b827",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            },
            "8ce09733f051c62daf304fa693f796dd087c349561e603b97848e250bcba4f7d": {
                "Name": "wireguard",
                "EndpointID": "c4084f1d73730750f62affe42494676560472fda39385e948a4805b5462d9491",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            }
        },

  • The host's /etc/resolv.conf (tried many variations of this, including just using a single IP from the container or the host)
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
# 127.0.0.53 is the systemd-resolved stub resolver.
# run "resolvectl status" to see details about the actual nameservers.
nameserver 172.19.0.2 # PiHole Container DNS
nameserver 10.0.0.18 #Host IP
127.0.0.53
  • Linux client /etc/wireguard/wg0.conf (also tried without the PostUp and PostDown):
[Interface]
Address = 10.0.1.2
PostUp = iptables -A FORWARD -o %i -j ACCEPT
PostDown = iptables -D FORWARD -o %i -j ACCEPT
PrivateKey = ...
ListenPort = 51820
DNS = 172.19.0.2 #Also tried with 10.0.0.18

[Peer]
PublicKey = ...
Endpoint = wireguard.domain.com:51820
AllowedIPs = 0.0.0.0/0
  • Enabled Listen on all interfaces, permit all origins in the PiHole Web Settings

  • PiHole docker-compose.yml

version: "3"

# More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    #network_mode: host
    networks:
      default:
      dns:
        ipv4_address: 172.19.0.2
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "67:67/udp"
      - "8001:80/tcp"
    environment:
      TZ: 'America/Arizona'
      WEBPASSWORD: '..'
    # Volumes store your data between container upgrades
    volumes:
      - './etc-pihole/:/etc/pihole/'
      - './etc-dnsmasq.d/:/etc/dnsmasq.d/'
#      - './lighttpd.conf:/etc/lighttpd/lighttpd.conf'
    # Recommended but not required (DHCP needs NET_ADMIN)
    #   https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
    cap_add:
      - NET_ADMIN
    restart: always

networks:
  dns:
    driver: bridge
    ipam:
      config: 
        - subnet: 172.19.0.0/16
          gateway: 172.19.0.1

  • Tried setting DELAY_STARTUP=5 in the pihole-FTL

  • Tried running the PiHole using the host network (DNS completely fails, even without vpn)

  • docker-compose.yml for Wireguard

version: "2.1"
services:
  wireguard:
    image: linuxserver/wireguard
    container_name: wireguard
    networks: 
      - 'pihole_dns'
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Arizona
      - SERVERURL=wireguard.domain.com #optional
      - SERVERPORT=51820 #optional
      - PEERS=10 #optional
      - PEERDNS=172.19.0.2 #optional
      - INTERNAL_SUBNET=10.0.1.0 #optional
      - ALLOWEDIPS=0.0.0.0/0 #optional
    volumes:
      - .:/config
      - .:/lib/modules
    ports:
      - 51820:51820/udp
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: always
networks:
  pihole_dns:
    external: true
  • Host iptables
$ sudo iptables -L -n -v

Chain INPUT (policy ACCEPT 2056 packets, 214K bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 3128 3000K DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 3128 3000K DOCKER-ISOLATION-STAGE-1  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 1461  483K ACCEPT     all  --  *      br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
   99  6985 DOCKER     all  --  *      br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
 1568 2510K ACCEPT     all  --  br-43a3a2d04f93 !br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 1276 packets, 135K bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    7   420 ACCEPT     tcp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.2           tcp dpt:80
    0     0 ACCEPT     udp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.2           udp dpt:67
    0     0 ACCEPT     tcp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.2           tcp dpt:53
   91  6389 ACCEPT     udp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.2           udp dpt:53
    1   176 ACCEPT     udp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.3           udp dpt:51820

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
 1568 2510K DOCKER-ISOLATION-STAGE-2  all  --  br-43a3a2d04f93 !br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
    0     0 DOCKER-ISOLATION-STAGE-2  all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
 3525 3051K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-ISOLATION-STAGE-2 (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
    0     0 DROP       all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
 1767 2522K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination         
 3525 3051K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0   

Anyone see anything I'm missing or can try?

Thanks.

Easy fix:

Add this to /etc/pihole/pihole-FTL.conf then restart Pi-Hole server.

DELAY_STARTUP=5

The problem happens when Pi-Hole is up already when WireGuard isn't so it works to access internal but cannot resolve DNS.

That lines delays Pi-Hole DNS start so that can happen after WireGuard is up.

This is covered in the official documentation but it is in the wrong place. This should be a default feature really.

Anyway

Tried it, didn't work :cry:

Just one of the reasons why I hate docker. It makes everything that simple more complex and problematic. Sure, only one command line and you bring everything up but.......

Back to your problem....

  1. Why is that 127.0.0.53 alone under /etc/resolv.conf?? Yeah, I read the top but when you complete Pi-Hole installation that file gets only a nameserver line pointing to itself. I run Debian11 on a RPI4 4GB and my file only has:

nameserver 192.168.1.4

Which is that Pi-Hole IP address.
I have 2x Pi4 4GB (Pi-Hole + Unbound Recursive DNS + WireGuard) exactly the same set as DNS on my router as primary and secondary. I can take one down at any time without breaking my home internet. So why I think that you don't need this over there.

  1. Also, within the same file I am confused with what is what 10.0.0.18 and 172.19.0.2 . It should only have the Pi-Hole IP-Address, nothing else, just like my env.

  2. No less important /etc/hosts
    It should have at least these two lines:

127.0.0.1 localhost
127.0.0.1 YOUR_SYSTEM_HOSTNAME

In my case tho, it would take ages to run apt-get and the solution was to add 127.1.1.0 instead of 127.0.0.1. There is a long forum somewhere explaining why this.

After installing Pi-Hole everything went back to normal

I am not by any means an expert, just trying to understand your env while thinking what I think that needs a closer look.

I hope the above helps you somewhat coz I am running out of ideas lol

Thanks for taking the time to offer some help, unfortunately it's still not working. I followed your setup, ensuring only my host IP is in /etc/resolv.conf, as well as setting up /etc/hosts properly.

If it's worth anything, here's also the output for sudo iptables -L -n -v

$ sudo iptables -L -n -v

Chain INPUT (policy ACCEPT 2056 packets, 214K bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 3128 3000K DOCKER-USER  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 3128 3000K DOCKER-ISOLATION-STAGE-1  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 1461  483K ACCEPT     all  --  *      br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
   99  6985 DOCKER     all  --  *      br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
 1568 2510K ACCEPT     all  --  br-43a3a2d04f93 !br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0           

Chain OUTPUT (policy ACCEPT 1276 packets, 135K bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    7   420 ACCEPT     tcp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.2           tcp dpt:80
    0     0 ACCEPT     udp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.2           udp dpt:67
    0     0 ACCEPT     tcp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.2           tcp dpt:53
   91  6389 ACCEPT     udp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.2           udp dpt:53
    1   176 ACCEPT     udp  --  !br-43a3a2d04f93 br-43a3a2d04f93  0.0.0.0/0            172.19.0.3           udp dpt:51820

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
 1568 2510K DOCKER-ISOLATION-STAGE-2  all  --  br-43a3a2d04f93 !br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
    0     0 DOCKER-ISOLATION-STAGE-2  all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0           
 3525 3051K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-ISOLATION-STAGE-2 (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      br-43a3a2d04f93  0.0.0.0/0            0.0.0.0/0           
    0     0 DROP       all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
 1767 2522K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-USER (1 references)
 pkts bytes target     prot opt in     out     source               destination         
 3525 3051K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0  

This seems to be more of a Docker and/or Wireguard issue than Pi-hole.

Just to make sure:
Do your Wireguard client configurations allow for accessing Pi-hole's IP address?

This may not produce the desired result, as it doesn't affect at all whether the Wireguard container would be running before bringing up Pi-hole's container.

Also note that by running both Wireguard and Pi-hole in separate containers, you are isolating their networking stacks, i.e. Pi-hole wouldn't be aware of the wireguard interface, and also your Pi-hole container isn't a Wireguard client, i.e. it doesn't have a Wireguard VPN IP.

Usually, you'd switch Pi-hole's Interface listening behaviour to one of its Listen on all... options for a VPN configuration. I wouldn't know whether traffic from the wireguard interface itself would be visible for Pi-hole if Wireguard is running in a separate container.

However, it should be sufficient if your Wireguard container would route DNS traffic from its 10.0.1.0 subnet to Pi-hole's Docker IP 172.19.0.2. You'd usually do that by adding respective iptables commands for NATing VPN traffic to your internal private network. Your own PostUp/PostDown rules seem a bit short.
I'm not familiar with running a dockered Wireguard, so I wouldn't know whether that would require additional iptables rules specifcially for Docker or not.

You may improve your chance for a more knowledgable answer by consulting other forums specialising in running Wireguard in a container.

I've got them working fine, but my use case is a bit different.

I have piHole and wireguard on a macvlan adaptor, so they both have unique IPs and avoid any port forwards, and both resolve/connect to each-other fine.

Ok, I've figured out the problem, but I don't know what the correct solution is.

The problem:

  • The iptable target NIC was wrong. Because I'm using a VM, my NIC is not the default eth0, but rather ens18.

I've tried to installed wireguard directly into my VM (not in docker) and got it to work. The wg0.conf for this is:

[Interface]
PrivateKey = ...
Address = 10.0.1.1/24
PreUp = iptables --table nat --append POSTROUTING --jump MASQUERADE --out-interface ens18
PreDown = iptables --table nat --delete POSTROUTING --jump MASQUERADE --out-interface ens18
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820

[Peer]
PublicKey = ...
AllowedIPs = 10.0.1.2/24

The key takeway from above is adding the PRE(UP/DOWN) append rules, and using ens18 NOT eth0 as the target output interface, courtesy of this stackoverflow

With the corresponding client config (below), I was able to connect to my LAN, access the internet, and access my internal service using my PiHole DNS :smiley:

[Interface]
Address = 10.0.1.2
PrivateKey = ...
ListenPort = 51820
DNS = 10.0.0.18 # <-- VM Host IP, NOT the container IP

[Peer]
PublicKey = ...
Endpoint = wireguard.domain.com:51820
AllowedIPs = 0.0.0.0/0

Now, I tried replicating the same wg0.conf above to the wg0.conf produced by docker, but couldn't not get it to work (no internet access).

For e.g., the wg0.conf that docker-compose generates is:

[Interface]
Address = 10.0.1.1
ListenPort = 51820
PrivateKey = 
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE

And I've tried adding the PRE append rules, and changing the eth0 to ens18, just like I did for the wireguard on my server, but unfortunately it has resulted in no internet access when wireguard is run in docker.

For e.g., here are some variations of wg0.conf I've tried to make it work, but with no internet access:

  • original docker wg0.conf for reference:
[Interface]
Address = 10.0.1.1
ListenPort = 51820
PrivateKey = ...

# The docker wg0.conf (connects with internet, but not DNS)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE
[Interface]
Address = 10.0.1.1
ListenPort = 51820
PrivateKey = ...

# The docker wg0.conf (connects with internet, but not DNS)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT #iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT #iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE

# The server wg0.conf (fully works at server level)
PreUp = iptables --table nat --append POSTROUTING --jump MASQUERADE --out-interface ens18
PreDown = iptables --table nat --delete POSTROUTING --jump MASQUERADE --out-interface ens18
#PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
#PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Interface]
Address = 10.0.1.1
ListenPort = 51820
PrivateKey = ...

# The docker wg0.conf (connects with internet, but not DNS)
#PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
#PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE

# The server wg0.conf (fully works at server level)
PreUp = iptables --table nat --append POSTROUTING --jump MASQUERADE --out-interface ens18
PreDown = iptables --table nat --delete POSTROUTING --jump MASQUERADE --out-interface ens18
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Interface]
Address = 10.0.1.1
ListenPort = 51820
PrivateKey = ...

# The docker wg0.conf (connects with internet, but not DNS)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE

# The server wg0.conf (fully works at server level)
PreUp = iptables --table nat --append POSTROUTING --jump MASQUERADE --out-interface ens18
PreDown = iptables --table nat --delete POSTROUTING --jump MASQUERADE --out-interface ens18
#PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
#PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Unfortuantley with these variations, I'm not able to successfully replicate my server wireguard with my docker wireguard. Anyone an experts with networking and docker that might have some insights?

Thanks!

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.