Configure WireGuard VPN with DNS filtering and ad blocking using Pi-hole and Unbound

Intermediate 45 min Apr 09, 2026 34 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up a secure WireGuard VPN server with integrated Pi-hole DNS filtering and Unbound recursive resolver for ad blocking and privacy protection. This configuration provides secure remote access while filtering malicious domains and advertisements.

Prerequisites

  • Root or sudo access
  • Static IP address or DDNS
  • Firewall access to configure port 51820
  • Basic understanding of DNS concepts

What this solves

A WireGuard VPN with Pi-hole and Unbound creates a secure tunnel that filters ads, trackers, and malicious domains at the DNS level. This setup provides privacy protection for remote devices while maintaining high performance through WireGuard's modern cryptography and Unbound's recursive DNS resolution.

Step-by-step configuration

Update system packages

Start by updating your package manager to ensure you get the latest security patches and package versions.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install required packages

Install WireGuard, Unbound recursive DNS resolver, and curl for Pi-hole installation.

sudo apt install -y wireguard unbound curl qrencode iptables-persistent
sudo dnf install -y wireguard-tools unbound curl qrencode iptables-services
sudo systemctl enable iptables

Configure Unbound recursive DNS resolver

Configure Unbound to handle DNS recursion and validation for improved privacy and performance.

server:
    verbosity: 0
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
    do-ip6: no
    prefer-ip6: no
    harden-glue: yes
    harden-dnssec-stripped: yes
    use-caps-for-id: no
    edns-buffer-size: 1232
    prefetch: yes
    num-threads: 1
    so-rcvbuf: 1m
    private-address: 192.168.0.0/16
    private-address: 169.254.0.0/16
    private-address: 172.16.0.0/12
    private-address: 10.0.0.0/8
    private-address: fd00::/8
    private-address: fe80::/10

Start and enable Unbound

Enable Unbound to start on boot and verify it's running on the correct port.

sudo systemctl enable --now unbound
sudo systemctl status unbound
dig @127.0.0.1 -p 5335 example.com

Install Pi-hole

Download and run the Pi-hole installation script with automated configuration.

curl -sSL https://install.pi-hole.net | bash

During installation, select the following options:

  • Choose your network interface
  • Select "Custom" for upstream DNS and enter 127.0.0.1#5335
  • Install the web admin interface
  • Install lighttpd web server
  • Enable query logging

Configure Pi-hole DNS settings

Set Pi-hole to use Unbound as the upstream DNS resolver for better privacy.

sudo pihole -a -p
sudo pihole restartdns

Access the Pi-hole web interface to verify the configuration:

echo "Pi-hole admin interface: http://$(hostname -I | awk '{print $1}')/admin/"

Add additional blocklists

Configure Pi-hole with comprehensive blocklists for enhanced ad blocking and security.

sudo pihole -w -l << 'EOF'
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
https://someonewhocares.org/hosts/zero/hosts
https://raw.githubusercontent.com/AdguardTeam/AdguardFilters/master/BaseFilter/sections/adservers.txt
https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext
EOF
sudo pihole -g

Generate WireGuard server keys

Create the cryptographic keys needed for the WireGuard server configuration.

sudo mkdir -p /etc/wireguard
cd /etc/wireguard
sudo wg genkey | sudo tee server_private_key | sudo wg pubkey | sudo tee server_public_key
sudo chmod 600 server_private_key

Configure WireGuard server

Create the main WireGuard server configuration with Pi-hole DNS integration.

[Interface]
PrivateKey = $(sudo cat /etc/wireguard/server_private_key)
Address = 10.8.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o $(ip route | awk '/default/ { print $5 }' | head -1) -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o $(ip route | awk '/default/ { print $5 }' | head -1) -j MASQUERADE
DNS = 10.8.0.1

Client configurations will be added here

Enable IP forwarding

Configure the system to forward packets between the VPN and external networks.

echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Configure Pi-hole to listen on WireGuard interface

Modify Pi-hole configuration to accept DNS queries from VPN clients.

sudo sed -i 's/PIHOLE_INTERFACE=.*/PIHOLE_INTERFACE=eth0,wg0/' /etc/pihole/setupVars.conf
sudo pihole restartdns

Create client configuration script

Create a script to easily generate client configurations with proper DNS settings.

#!/bin/bash

CLIENT_NAME="$1"
if [ -z "$CLIENT_NAME" ]; then
    echo "Usage: $0 "
    exit 1
fi

SERVER_PUBLIC_KEY=$(sudo cat /etc/wireguard/server_public_key)
SERVER_IP=$(curl -s ifconfig.me || curl -s icanhazip.com)
CLIENT_PRIVATE_KEY=$(wg genkey)
CLIENT_PUBLIC_KEY=$(echo $CLIENT_PRIVATE_KEY | wg pubkey)
CLIENT_IP="10.8.0.$(($(sudo wg show wg0 2>/dev/null | grep -c peer) + 2))"

Add client to server config

echo "" | sudo tee -a /etc/wireguard/wg0.conf echo "# $CLIENT_NAME" | sudo tee -a /etc/wireguard/wg0.conf echo "[Peer]" | sudo tee -a /etc/wireguard/wg0.conf echo "PublicKey = $CLIENT_PUBLIC_KEY" | sudo tee -a /etc/wireguard/wg0.conf echo "AllowedIPs = $CLIENT_IP/32" | sudo tee -a /etc/wireguard/wg0.conf

Generate client config

cat > "/tmp/${CLIENT_NAME}.conf" << EOF [Interface] PrivateKey = $CLIENT_PRIVATE_KEY Address = $CLIENT_IP/32 DNS = 10.8.0.1 [Peer] PublicKey = $SERVER_PUBLIC_KEY AllowedIPs = 0.0.0.0/0 Endpoint = $SERVER_IP:51820 PersistentKeepalive = 25 EOF echo "Client configuration saved to /tmp/${CLIENT_NAME}.conf" echo "QR code for mobile devices:" qrencode -t ansiutf8 < "/tmp/${CLIENT_NAME}.conf"

Restart WireGuard to apply changes

sudo systemctl restart wg-quick@wg0
sudo chmod 755 /usr/local/bin/wg-client

Configure firewall rules

Set up firewall rules to allow WireGuard traffic and protect the server.

sudo ufw allow 51820/udp comment 'WireGuard'
sudo ufw allow 80/tcp comment 'Pi-hole HTTP'
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw --force enable

Start WireGuard server

Enable and start the WireGuard VPN server with the configured interface.

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo systemctl status wg-quick@wg0

Create your first VPN client

Generate a client configuration file for connecting to your VPN.

sudo wg-client laptop
cat /tmp/laptop.conf

Configure custom DNS filtering rules

Add custom domains to Pi-hole blocklist and whitelist for fine-tuned filtering.

# Block additional domains
sudo pihole -b malicious-domain.com tracking-service.net

Whitelist legitimate services that might be blocked

sudo pihole -w legitimate-service.com cdn-provider.net

View current lists

sudo pihole -q -exact blocked-domain.com

Verify your setup

Test your WireGuard VPN and DNS filtering configuration.

# Check WireGuard status
sudo wg show
sudo systemctl status wg-quick@wg0

Verify Pi-hole is blocking ads

dig @10.8.0.1 doubleclick.net nslookup ads.google.com 10.8.0.1

Test Unbound recursive resolution

dig @127.0.0.1 -p 5335 example.com

Check Pi-hole query logs

tail -f /var/log/pihole.log

Verify firewall rules

sudo ufw status verbose

On a connected client, test DNS filtering:

# Should be blocked by Pi-hole
nslookup doubleclick.net

Should resolve normally

nslookup example.com

Check your external IP (should show VPN server IP)

curl ifconfig.me

Common issues

SymptomCauseFix
Client can't connect to VPN Firewall blocking WireGuard port sudo ufw allow 51820/udp
DNS queries not filtered Pi-hole not listening on VPN interface Add wg0 to PIHOLE_INTERFACE in setupVars.conf
No internet through VPN IP forwarding disabled echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
Unbound not resolving Wrong port configuration Verify Unbound runs on port 5335: sudo netstat -tulpn | grep 5335
Pi-hole web interface unreachable Lighttpd not running sudo systemctl restart lighttpd
VPN connected but slow DNS DNS timeout issues Check Pi-hole logs: tail -f /var/log/pihole.log
Security note: Never use chmod 777 on WireGuard keys. Private keys should be 600 (readable only by owner) and owned by root for security.

Next steps

Automated install script

Run this to automate the entire setup

#wireguard #vpn #pi-hole #dns-filtering #unbound #ad-blocking #privacy #network-security

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer