Setting up a PiHole + Wireguard VPN Server

Date: 2020-5-3

Last Edited: 2020-5-12

Note: For the rest of this guide I'll use the $ symbol for commands that should be entered as a regular user and # for commands that should be executed as root.

Setting up the Pi-Hole

First, I flashed a 32 GB Samsung EVO SD card with the raspbian buster lite image by running the following commands:

$ curl -O -L http://downloads.raspberrypi.org/raspbian/images/raspbian-2020-02-14/2020-02-13-raspbian-buster.zip
$ sha256-sum 2020-02-13-raspbian-buster.zip
12ae6e17bf95b6ba83beca61e7394e7411b45eba7e6a520f434b0748ea7370e8  2020-02-13-raspbian-buster-lite.zip
$ unzip -p 2020-02-13-raspbian-buster-lite.zip | sudo dd of=/dev/sdX bs=4M conv=fsync

where /dev/sdX is the device name for the SD card.

Next, we need to mount the boot partition and enable ssh:

$ sudo mount /dev/sda1 /media/usb-drive
$ sudo touch /media/usb-drive/ssh
$ sudo sync
$ sudo umount /media/usb-drive

Ok, now you should be able to put the SD card in the Raspberry Pi and hook it up to your switch or router. Once it boots up and you discover the ip address you can ssh it to it like so:

$ ssh pi@192.168.1.109

And then run

$ sudo raspi-config

and change the default password for the user and enable SSH by going to Interfacing Options -> SSH.

Next, you can install Pi-Hole with:

$ wget -O basic-install.sh https://install.pi-hole.net
$ chmod +x ./basic-install.sh
$ sudo ./basic-install.sh

After completing the installation, you can change the default admin password with:

$ pihole -a -p

Next you should reconfigure your router to use the Pi-Hole as the primary DNS server. In my case that was 192.168.1.109. You can then verify that it is working by logging into the WiFi network and navigating to http://pi.hole which should resolve to the web interface if everything is set up properly.

Installing Wireguard

To install wireguard, we first need to enable the unstable buster-backports repository:

# vim /etc/apt/sources.list.d/backport.list

and add:

deb http://deb.debian.org/debian buster-backports main

Next, run

# apt-get update

If you get an error about gpg keys, you will have to add those keys (I can't remember exactly how I did this).

I then installed wireguard by running:

# apt-get -t buster-backports install wireguard

I then followed the instructions starting at the "Set Up and Configure the Wireguard Server" section at https://engineerworkshop.com/2020/02/20/how-to-set-up-wireguard-on-a-raspberry-pi/ to finish setting up everything. You should make sure to set the DNS IP address for the clients to the IP address you used for the server (10.253.3.1 if you use the values in the instructions).

If you're trying to connect from a phone, it's very handy to be able to generate a QR code from the wireguard client configuration file. To do so you can run the following command:

# qrencode -t ansiutf8 -r wg0-client.conf

assuming your terminal supports UTF8 (I had to use urxvt for some reason).

You can test out if things are working by connecting to the VPN and then navigating to http://pi.hole and verifying that you get the pihole webpage. If not, you may need to log in to the pihole admin page and go to Settings -> DNS and tweak the "Interface Listening Behavior" setting.

Fail2Ban

$ apt install fail2ban
$ cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
$ vim /etc/fail2ban/jail.local

Add the following lines under the [sshd] section (based on https://pimylifeup.com/raspberry-pi-fail2ban ):

enabled = true
filter = sshd
ban-action = iptables-multiport
bantime = -1
maxretry = 3

Then you can restart the service with:

# service fail2ban restart

IPTables

First we'll install the iptables persistent package so that our iptables rules persist after reboots:

# apt-install iptables-persistent

Here are the rules I set up for iptables:

# Generated by xtables-save v1.8.2 on Mon May  4 03:57:58 2020
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -s 10.0.0.0/24 -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -s 10.0.0.0/24 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 51900 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -s 192.168.1.0/24 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -p udp -m udp --dport 51900 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -i wg0 -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
COMMIT
# Completed on Mon May  4 03:57:58 2020
# Generated by xtables-save v1.8.2 on Mon May  4 03:57:58 2020
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# Completed on Mon May  4 03:57:58 2020

You can set this up by creating a file called /etc/iptables/rules.v4 with the previous lines and then running:

# iptables-restore /etc/iptables/rules.v4