In this guide we will see how to set up a VPN server with advertisement blocking capabilities using Debian, Wireguard and PiHole. To follow this guide, make sure
to have an updated installation of Debian; at the time of writing the latest version available is Debian 11, but any newer version should also work. For the rest of the tutorial we will be using the
firewalld firewall, but you can use any other netfilter frontend of your choice.
Let us start by installing
marco@vpnnode:~$ sudo apt install wireguard firewalld
and let us enable the firewall daemon at boot:
marco@vpnnode:~$ sudo systemctl enable firewalld --now
Let us now start configuring the wireguard server by generating the keypair and the configuration file; to do so, we will create a dedicated directory:
root@vpnnode:~# mkdir -p /etc/wireguard/ root@vpnnode:~# cd /etc/wireguard/
Once inside it, we can generate a new keypair with the
root@vpnnode:/etc/wireguard# wg genkey | tee privkey | wg pubkey > pubkey root@vpnnode:/etc/wireguard# ls -lh total 8.0K -rw-r--r-- 1 root root 45 Aug 6 08:46 privkey -rw-r--r-- 1 root root 45 Aug 6 08:46 pubkey root@vpnnode:/etc/wireguard# cat privkey +LoX/Rrh2VR6nFiExOweXR37HluHdOhjBiFu7jqK7mo=
at this point, copy the content of privkey file and create a new file called
PrivateKeyis equal to the content of
Addressis the CIDR mask of the VPN(i.e. from
ListenPortis the UDP port where the Wireguard server will listen to.
You should have a similar structure:
root@vpnnode:/etc/wireguard# cat wg0.conf [Interface] PrivateKey = +LoX/Rrh2VR6nFiExOweXR37HluHdOhjBiFu7jqK7mo= Address = 192.168.2.1/24 ListenPort = 48965
Configure the firewall⌗
The next step is to configure the firewall to listen to the selected UDP port and to create a NAT between the internal Wireguard interface(
wg0) and the server’s external interface(in my case
enp1s0). To do that, issue the following commands:
root@vpnnode:/etc/wireguard# firewall-cmd --permanent --add-port=48965/udp root@vpnnode:/etc/wireguard# firewall-cmd --permanent --add-masquerade root@vpnnode:/etc/wireguard# firewall-cmd --reload root@vpnnode:/etc/wireguard# firewall-cmd --list-all public target: default icmp-block-inversion: no interfaces: sources: services: dhcpv6-client ssh ports: 48965/udp protocols: forward: no masquerade: yes forward-ports: source-ports: icmp-blocks: rich rules:
After reloading the firewall rules, you should have a new udp port open and the IP masquerading activated for the public firewall zone. Now let us do the same thing for the
wg0 interface on the internal firewall zone:
root@vpnnode:/etc/wireguard# firewall-cmd --zone=internal --add-interface=wg0 root@vpnnode:/etc/wireguard# firewall-cmd --permanent --zone=internal --add-masquerade root@vpnnode:/etc/wireguard# firewall-cmd --zone=internal --list-all internal target: default icmp-block-inversion: no interfaces: sources: services: dhcpv6-client mdns samba-client ssh ports: protocols: forward: no masquerade: yes forward-ports: source-ports: icmp-blocks: rich rules:
Routing is complete, the last thing to do is to enable ip forwarding.
Enable IP forwarding⌗
In order to route packets between VPN’s clients and a remote host, we need to enable the ip forwarding feature. To do so, type the following command:
root@vpnnode:/etc/wireguard# sysctl -w net.ipv4.ip_forward=1 net.ipv4.ip_forward = 1
and to make it permanent, edit the
/etc/sysctl.d/99-sysctl.conf file and uncomment the following line:
# Uncomment the next line to enable packet forwarding for IPv4 net.ipv4.ip_forward=1
Wireguard can be installed in wide spectrum of operating system, in this guide I will not cover the installation processing, in order to install the wireguard client for your computer/table/phone, please refer to this page. After that, open up the configuration file and add the following content:
[Interface] PrivateKey = ni16f/oyWn8G0rdsJ7YGyytjXvJSfaNzhzFSG5Bv4Gg= # <-- client private key Address = 192.168.2.2/24 DNS = 192.168.2.1 [Peer] PublicKey = 4wzgj/0u53Jiheq8DjwQ9GRnvnzv0qcsisKARdnrr1c= # <-- server public key PresharedKey = PW21sz8kl+nY8WRNJEypkqWJGLARSX2A5KjbPfaEUp0= # <-- wg genpsk AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = <SERVER_IP_ADDRESS>:48965 PersistentKeepalive = 15
Be sure to replace the following fields according to your needs:
PrivateKey: replace it with client’s private key(you can generate a new keypair using
wg genkey | tee privkey | wg pubkey > pubkeycommand if you do not use a graphical client);
PublicKey: replace with server’s public key(i.e.
/etc/wireguard/pubkeyfile on the VPN server);
PresharedKey: you can generate a preshared key with
wg genpsk(this field is optional);
Endpoint: the IP address of your server with the Wireguard UDP port.
Let us now complete the configuration by adding a new client in the server configuration file.
Back to the server⌗
/etc/wireguard/wg0.conf file and add the following entry at the end:
[Interface] PrivateKey = +LoX/Rrh2VR6nFiExOweXR37HluHdOhjBiFu7jqK7mo= Address = 192.168.2.1/24 ListenPort = 48965 # Add this [Peer] PublicKey = 1+54fGF/zZlVTxDiJ3rlmrH65+5K1NMFKwxlniA/2js= # <-- Client public key PresharedKey = PW21sz8kl+nY8WRNJEypkqWJGLARSX2A5KjbPfaEUp0= AllowedIPs = 192.168.2.2/32
PublicKeyis the public key of the client;
PresharedKeyis the preshared key previously generated on the client configuration;
AllowedIPsis the client’s IP address.
This means that every time you want to add a new client to the network, you create a new keypair, and then you add the public key to the server configuration file. Just be sure to assign a unique IP address to each client.
Finally, let us start the Wireguard server:
root@vpnnode:/etc/wireguard# systemctl enable wg-quick@wg0 --now root@vpnnode:/etc/wireguard# wg interface: wg0 public key: 4wzgj/0u53Jiheq8DjwQ9GRnvnzv0qcsisKARdnrr1c= private key: (hidden) listening port: 48965 peer: 1+54fGF/zZlVTxDiJ3rlmrH65+5K1NMFKwxlniA/2js= preshared key: (hidden) allowed ips: 192.168.2.2/32
You can now enable the VPN connection from your client. Right now, you will only be able to ping the VPN gateway(
192.168.2.1) without being able to access the internet. This is normal because the DNS server we have specified in the client’s configuration file(i.e.
192.168.2.1) is not active. We will fix this in a second by installing PiHole.
PiHole is an internet tracking blocking system which acts as a DNS sinkhole. It is designed primarily for embedded devices such as the RaspberryPi, but it can be easily installed on any other Linux operating system. Since PiHole makes use of different daemons(such as a DNS server, lighttpd and the AdminLTE dashboard) that require some configuration, we will launch it using Docker.
Installing Docker on Debian is outside the scope of this guide, so please refer to the official documentation.
After docker is ready, set up a password for the PiHole dashboard(i.e. the password needed to log in to the web interface) and launch the docker containers with the following parameters:
marco@vpnnode:~$ PW="qwerty" # Choose a better password than mine :P marco@vpnnode:~$ docker run -d \ --name pihole \ -p 192.168.2.1:53:53/tcp -p 192.168.2.1:53:53/udp \ -p 192.168.2.1:8888:80 \ -e TZ="Europe/Frankfurt" \ -e WEBPASSWORD=$PW \ --dns=127.0.0.1 --dns=22.214.171.124 \ --restart=unless-stopped \ pihole/pihole:latest
Wait a few seconds for the container to start up, when it’s ready you should see the status healthy in the docker logs:
marco@vpnnode:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4dca0568e347 pihole/pihole:latest "/s6-init" 40 seconds ago Up 39 seconds (healthy) 192.168.2.1:53->53/tcp, 192.168.2.1:53->53/udp, 67/udp, 192.168.2.1:8888->80/tcp pihole
Finally, let us configure PiHole to listen to our network interface. To do so, open up your browser and go to the admin page(be sure to be connected to the VPN, PiHole does not expose the port 8888/80 to the external interface). You should see a page like this:
Enter your password and follow these instructions:
- Go to “settings” in the left pane;
- Go to the “DNS” tab;
- Selected the “Respond only on interface eth0” radio button in the “interface settings” section.
After that go to the bottom of the page and click the “save” button.
At this point you should be able to reach the internet. Let us try our new VPN on some sites(apart from whatismyipaddress.com):
Go to this page if you are using Cloudflare’s DNS:
This page check if our ads blocking system works(you can also try to open any newspaper website with adblock disabled…those websites are the perfect testing page for an anti-ads system):
This website check if your VPN/DNS leaks your real IP address:
This page determines whether your DNS resolver validates DNSSEC signatures.