WireGuard VPN + PiHole Setup

07/08/2024


article cover

Introduction


Unlike the other separate guides for PiHole and WireGuard, in this guide we will see how to set up a VPN server with advertisement blocking capabilities using Wireguard and PiHole, essentially merging both and making them work together for a more seamless process.

Why combine WireGuard and PiHole?


Combining WireGuard with Pi-Hole offers a powerful duo for enhancing both privacy and network security. WireGuard provides a secure, encrypted VPN tunnel that protects your data and masks your online activities from external threats. Meanwhile, Pi-Hole blocks unwanted ads, trackers, and malicious domains at the network level, improving browsing speed and protecting your privacy. Together, they create a robust setup where your online traffic is both encrypted and free from intrusive ads, ensuring a safer and more enjoyable internet experience.

Installation


If you already have either PiHole or WireGuard setup separately - make sure to remove them altogether, so that we can add both at once and put them in the same subnet and assign static IPs for them.

Before proceeding, make sure to hash your desired password by running the below command:

docker run -it ghcr.io/wg-easy/wg-easy wgpw YOUR_PASSWORD

The output will be a bcrypt hash like: "$2y$10$hBCoykrB95WSzuV4fafBzOHWKu9sbyVa34GJr8VV5R/pIelfEMYyG"

Since we will be using docker-compose, anywhere you have the "$" symbol, make sure to add an extra one, so "$$" and copy the hash.

Now, we can proceed with the rest:

  1. Create and open the directory

    mkdir wireguard && cd wireguard
  2. Create a docker file

    nano docker-compose.yml
  3. Paste the below and replace "your_hash" with the hash you've made in the previous steps:

    version: "3"
    volumes:
    etc_wireguard:
    services:
    wg-easy:
    environment:
      # Change Language:
      # (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th, hi)
        - LANG=en
      # Required:
        - WG_HOST=172.20.1.3
      # Optional:
        - PASSWORD_HASH=your_hash
      # - WG_PORT=51820
      # - WG_DEFAULT_ADDRESS=10.8.0.0
      # - WG_DEFAULT_ADDRESS_RANGE=24
      # - WG_DEFAULT_DNS=1.1.1.1
      # - WG_MTU=1420
      - WG_ALLOWED_IPS=0.0.0.0/0, ::/0
      # - WG_PERSISTENT_KEEPALIVE=25
      # - WG_PRE_UP=echo "Pre Up" > /etc/wireguard/pre-up.txt
      # - WG_POST_UP=echo "Post Up" > /etc/wireguard/post-up.txt
      # - WG_PRE_DOWN=echo "Pre Down" > /etc/wireguard/pre-down.txt
      # - WG_POST_DOWN=echo "Post Down" > /etc/wireguard/post-down.txt
      # - UI_TRAFFIC_STATS=true
      # - UI_CHART_TYPE=0 (0 # Charts disabled, 1 # Line chart, 2 # Area chart, 3 # Bar chart)
    image: ghcr.io/wg-easy/wg-easy
    container_name: wg-easy
    volumes:
      - etc_wireguard:/etc/wireguard
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
    networks:
      wg-easy:
        ipv4_address: 172.20.1.2
    pihole:
    container_name: pihole
    image: pihole/pihole:latest
    # For DHCP it is recommended to remove these ports and instead add: network_mode: "host"
    labels:
      - "com.centurylinklabs.watchtower.enable=false"
    ports:
      - "53:53/tcp" # Host Port:Container Port
      - "53:53/udp"
      # - "67:67/udp" # Only required if you are using Pi-hole as your DHCP server
      - "80:80/tcp"
    environment:
      TZ: 'England/London'
      WEBPASSWORD: 'your_password'
    # Volumes store your data between container upgrades
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    #   https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
    cap_add:
      - NET_ADMIN # Required if you are using Pi-hole as your DHCP server, else not needed
    networks:
      wg-easy:
        ipv4_address: 172.20.1.3
    restart: unless-stopped
    networks:
    wg-easy:
    ipam:
      config:
        - subnet: 172.20.1.0/24
  4. Save with CTRL+X, Y, Enter

  5. Deploy the container

    docker-compose up -d
  6. Confirm that it deployed successfully

    docker ps
  7. Port Forward port 51820 (UDP) to the host's local IP from the router settings

  8. Open the PiHole WebUI at localhost/admin (e.g., 192.168.100.186/admin)

  9. Navigate to "Settings -> DNS" and change the DNS provider to Cloudflare and ensure that the Interface Setting is set to "Respond only on interface eth0"

Installation (Client)


  1. Download the WireGuard from AppStore/GooglePlay
  2. Navigate to localhost:51821, add user, and generate QR code
  3. Scan the QR code with the client device
  4. Ensure the Endpoint is set to PublicIP:51820 and DNS is set to 172.20.1.3, which should be your PiHole's container local IP

Firewall Port Configuration


If you do have a firewall in place, make sure that you've properly allowed the requried ports in the firewall. In case you need assistance with this - check my guide for UFW here.