Raspberry Pi with Pi-hole ¶
This runs wg-access-server next to Pi-hole with Docker Compose, so that
devices connected to the VPN get Pi-hole's ad and tracker blocking wherever they are. It works the
same on any other Docker host; both images are published for the Raspberry Pi (arm64 and arm/v7).
The VPN clients use wg-access-server's DNS server (10.44.0.1, the default), which forwards their
queries to Pi-hole. Pi-hole itself is only reachable from inside Docker - it does not have to answer
anybody else, and port 53 of the host stays free.
Prerequisites ¶
- Docker with the Compose plugin
- The WireGuard kernel module. Raspberry Pi OS Bookworm and newer ship it; check with
sudo modprobe wireguard. See Docker for loading it on boot. - UDP port 51820 forwarded to the Raspberry Pi if clients connect from outside your network
docker-compose.yml ¶
services:
pihole:
image: pihole/pihole:latest
container_name: pihole
environment:
TZ: "Europe/Berlin"
FTLCONF_webserver_api_password: "${PIHOLE_PASSWORD:?please set PIHOLE_PASSWORD}"
volumes:
- "pihole-data:/etc/pihole"
ports:
- "8080:80/tcp" # Pi-hole's web interface
networks:
dns:
ipv4_address: 172.30.0.53
restart: unless-stopped
wg-access-server:
image: ghcr.io/freifunkmuc/wg-access-server:latest
container_name: wg-access-server
cap_add:
- NET_ADMIN
sysctls:
net.ipv6.conf.all.disable_ipv6: 0
net.ipv6.conf.all.forwarding: 1
environment:
WG_ADMIN_PASSWORD: "${WG_ADMIN_PASSWORD:?please set WG_ADMIN_PASSWORD}"
WG_WIREGUARD_PRIVATE_KEY: "${WG_WIREGUARD_PRIVATE_KEY:?please set WG_WIREGUARD_PRIVATE_KEY}"
# the VPN clients' DNS server forwards to Pi-hole
WG_DNS_UPSTREAM: "172.30.0.53"
volumes:
- "wg-access-server-data:/data"
ports:
- "8000:8000/tcp"
- "51820:51820/udp"
devices:
- "/dev/net/tun:/dev/net/tun"
networks:
- dns
depends_on:
- pihole
restart: unless-stopped
networks:
dns:
ipam:
config:
- subnet: 172.30.0.0/24
volumes:
pihole-data:
wg-access-server-data:
Pi-hole gets a fixed address in a network of its own, so wg-access-server can name it as its upstream. Both containers are in that network, so Pi-hole's default of only answering its local network is all that is needed.
Start it ¶
export PIHOLE_PASSWORD="<a password for Pi-hole's web interface>"
export WG_ADMIN_PASSWORD="<a password for wg-access-server>"
export WG_WIREGUARD_PRIVATE_KEY="$(wg genkey)"
docker compose up -d
Keep the private key: the device configurations handed out so far only work with it. Put the
variables into an .env file next to docker-compose.yml to have them at the next start.
Then add a device in wg-access-server at http://<raspberry-pi>:8000 and connect. Pi-hole's web
interface at http://<raspberry-pi>:8080/admin shows the queries of the VPN clients - all coming
from wg-access-server's address, because it forwards them.
Check that it works ¶
From a connected device, look up a domain that Pi-hole blocks:
nslookup doubleclick.net 10.44.0.1
The answer is 0.0.0.0 when the query went through Pi-hole. On the first start Pi-hole needs a
minute or so to download its block lists; until then it answers everything.