Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Haprog/5ed115bac78ba4b362f91b102d721d0a to your computer and use it in GitHub Desktop.
Save Haprog/5ed115bac78ba4b362f91b102d721d0a to your computer and use it in GitHub Desktop.
Installing Pi-Hole, Unbound and a WireGuard VPN server on a Raspberry Pi (via Docker)

Updated: 2022-07

Raspberry Pi-Hole VPN Setup

I wrote the first edition of this as a guide for myself at the end of 2017 - it was a mashup of Pi-Hole + PiVPN scripts and an IPsec script installed within a separate Raspian Docker image... and it actually worked!

But things have come a long way, and WireGuard happened - I've since streamlined and simplified my setup into a single Docker Compose script.

The steps below assume the following:

  • You have the minimum hardware for running a Raspberry Pi
    (I'm still using the same Raspberry Pi 2 over Ethernet)
  • You know what Pi-Hole is for
  • You know what Unbound is for
  • You know what WireGuard is for
  • You know how to run a Docker Compose script
  • Basic networking knowledge (DHCP, IPs, etc.)
  • Comfortable around the Terminal / Putty, and text editing config files.

Pi OS Lite

  1. Install latest Pi OS Lite using the Raspberry Pi Imager
    • Either:
      Use the Pi Imager options to enable SSH and pre-configure the user credentials (press the Cog button before Write).
    • Or:
      Use the Headless Raspberry Pi steps on the official docs to do the setup manually.
  2. Plug the Pi into the network and power it on
  3. Once booted, retrieve its initial IP (via router settings, IP scan, etc.) and remote in:
  4. Update everything, then run the Configurator:
    sudo apt-get update
    sudo apt-get upgrade -y
    sudo raspi-config
  5. Configure base Pi settings to your liking
    • (These settings are particularly recommended):
      • System Options > Network at Boot: Yes
      • Performance Options > GPU Memory: 16
  6. Setup the Pi to use a Static IP Address
  7. Reboot the Pi and login to the new static IP address
  8. Install log2ram (Optional, but recommended)
  9. Install Docker

Docker Folders

  1. Create the following folders for each app to keep their persistent configs:

    mkdir -p ~/docker/pihole-data/etc-dnsmasq.d/
    mkdir -p ~/docker/pihole-data/etc-pihole/
    mkdir -p ~/docker/unbound-data/
    mkdir -p ~/docker/wireguard-data/
  2. Navigate into the Unbound config folder:

    cd ~/docker/unbound-data/
  3. Create the Unbound config file using the example from the Pi-Hole + Unbound docs.

    • Instead of saving it as pi-hold.conf though, save the config file as: ~/docker/unbound-data/unbound.conf
  4. Add the following lines to the bottom of the config file:

    # Allow lookups from these blocks (needed when running from inside Docker)
    access-control: 172.16.0.0/12 allow
    access-control: 127.0.0.0/8 allow
    access-control: 10.0.0.0/8 allow
    access-control: 192.168.0.0/16 allow
    
    # Allow Plex DNS things (if using Plex)
    private-domain: plex.direct
    
  5. Edit and run the compose script below where:

    • ip.address.of.pi is the internal static IP of the Pi
    • external.domain.com is the external domain or IP of your network (that the VPN client will use to connect on)
    • vpnUser1,vpnUser2 is the comma-separated list of VPN users to create for WireGuard access
version: "3"
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
network_mode: host
environment:
- TZ=Europe/London # Edit this
- WEBPASSWORD=PIHOLE_PASSWORD # Edit this
- ServerIP=ip.address.of.pi # Edit this
- DNS1=127.0.0.1#5335
volumes:
- /home/pi/docker/pihole-data/etc-pihole:/etc/pihole
- /home/pi/docker/pihole-data/etc-dnsmasq.d:/etc/dnsmasq.d
cap_add:
- NET_ADMIN
restart: always
unbound:
container_name: unbound
image: mvance/unbound-rpi:latest
network_mode: host
volumes:
- /home/pi/docker/unbound-data:/opt/unbound/etc/unbound
healthcheck:
disable: true
restart: always
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: wireguard
hostname: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/London # Edit this
- SERVERURL=external.domain.com # Edit this
- PEERS=vpnUser1,vpnUser2 # Edit this
- PEERDNS=ip.address.of.pi # Edit this
# Need to also set "Bind only to interface eth0" or "Permit all origins" in PiHole DNS settings
- LOG_CONFS=false
volumes:
- /home/pi/docker/wireguard-data:/config
- /lib/modules:/lib/modules
ports:
- 51820:51820/udp
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: always

Post-Setup

  • Once the containers are running, navigate to the Pi-Hole admin page:
  • Configure your router to forward the WireGuard Port UDP 51820 to your Raspberry Pi
  • WireGuard user credentials / QR codes can be found in:
    • The ~/docker/wireguard-data/peer_* folders
    • Could also run the following command to show the QR code directly on the command line: (replace with your target VPN username)
      docker exec -it wireguard /app/show-peer vpnUser1
  • If Unbound starts up with an error that looks like:
    [1658509728] unbound[1:0] warning: so-rcvbuf 1048576 was not granted. Got 360448. To fix: start with root permissions(linux) or sysctl bigger net.core.rmem_max(linux) or kern.ipc.maxsockbuf(bsd) values.
    
    Add the following line to the bottom of /etc/sysctl.conf
    net.core.rmem_max=1048576
    
    Source: MatthewVance/unbound-docker-rpi#4 (comment)

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment