I’ve been using Pi-hole for almost two years now, and it has become one of my favorite privacy projects. In a nutshell, Pi-hole blocks unwanted content, like advertisements and trackers, at a DNS level, so they will never be loaded. Pi-hole is open source and can be installed on your own Linux hardware to be used network-wide as a DNS server. This means it will even block unwanted content on your smartphone and console without installing any client-side apps. Pi-hole blocks 10-30% of all queries in my LAN (with over 550,000 domains on the blocklist).
To benefit from Pi-hole wherever I am (traveling or working from somewhere else), I run my own OpenVPN server on the same hardware, a Raspberry Pi 3 Model B. In fact, I always use my VPN when outside of my LAN, because you really shouldn’t trust public WiFi.
The Raspberry Pi 3 has more than enough resources for both, the only limiting factor is its network interface that is hampered by the USB 2.0 bus speed. This means if you’re using the onboard LAN your VPN connection will top out at about 94.4 Mbits/sec (11.8 MB/sec) no matter your Internet upload speed. If you’ve a faster upload connection Jeff Geerling almost doubled the throughput with an USB Gigabit LAN adapter.
Install OpenVPN with PiVPN
First, if you don’t have a static Internet IP address from where you host the Raspberry Pi, map a domain to your dynamic IP address, so that you can use it in your VPN setup. Otherwise you’d need to always know your current Internet IP address to connect to your VPN, which can be hard to get when you’re offsite. I’ve used the free dynamic DNS service from ChangeIP (now I’d use CloudFlare) and ddclient to update my IP regularly. In the below example we map “vpn.yourdomain.com”.
sudo apt-get install ddclient libio-socket-ssl-perl
Edit the config:
sudo vi /etc/ddclient.conf
# ddclient.conf # tell ddclient how to get your ip address use=web, web=ip.changeip.com # provide server and login details protocol=changeip ssl=yes server=nic.changeip.com/nic/update login=<login> password=<pw> # specify the domain to update vpn.yourdomain.com
To update the mapping regularly, add ddclient as a daemon.
Edit the config:
sudo vi /etc/default/ddclient
run_daemon="true"` daemon_interval=900` # every 15 minutes
Start the daemon afterwards with
sudo service ddclient start. Its status can be checked with
sudo service ddclient status.
ddclient caches the IP and only updates it on a change. However some dynamic DNS services require a daily/weekly update or the account gets closed. This is why we create a cronjob (needs root) to force an update even if the IP didn’t change:
sudo crontab -e
0 4 * * * /usr/sbin/ddclient -force >/home/pi/logs/ddclient.log 2>&1
Now to the installing of OpenVPN itself. An easy way to setup your own OpenVPN server on a Raspberry Pi is PiVPN—a set of install and management shell scripts to set it up in a fraction of the time. It comes with hardened security settings by default. The install process is well explained, so there’s no point to repeat it here. Just remember to use your domain (vpn.yourdomain.com) for the IP, if you’ve mapped it before with ddclient. I use the open source OpenVPN client Tunnelblick to connect to my VPN.
Note: Don’t forget to have your router forward UDP port 1194.
Install Pi-hole with OpenVPN support
Prerequisites: It’s not a must, but I recommend to set a static IP address for your Raspberry Pi in your LAN. For this guide I assume you’ve done that.
I use the alternative install method, as I’m not a fan of curling and piping to bash:
git clone --depth 1 https://github.com/pi-hole/pi-hole.git Pi-hole cd "Pi-hole/automated install/" sudo bash basic-install.sh
My Pi-hole settings:
- Network interface: eth0 (so that it also works if we aren’t connected through the VPN)
- Enable: DNS > Never forward non-FQDNs
- Enable: DNS > Never forward reverse lookups for private IP ranges
- Enable: DNS > Use DNSSEC
- Select: DNS > Listen on all interfaces
- Select: Privacy > Level 3 privacy mode (anonymous mode) to disable logs (easier on the sd card).
If you want to add more than the default blocklists, here are mine.
Finally, replace your router’s DNS server with the static IP address of the Raspberry Pi, and all clients in the network should benefit from Pi-hole.
Add OpenVPN support
/etc/dnsmasq.conf and add the static Raspberry Pi IP address and the OpenVPN IP:
listen-address=127.0.0.1, 192.168.0.100, 10.8.0.1
To use Pi-hole for VPN connections and without, create the file
/etc/dnsmasq.d/ with the required interfaces:
interface=tun0 # OpenVPN interface=eth0
sudo service dnsmasq force-reload
That’s it. Now you can connect from everywhere to your OpenVPN server, and Pi-hole will keep you sane from unwanted content.
Hosting web services on the same hardware
Pi-hole comes with
lighttpd (and global rewriting rules) build-in, while it’s possible to use the same
lighttpd instance for other web services, I’ve found it easier to use and maintain
nginx on a secondary IP address, isolated from Pi-hole, to host other web services on the same hardware.
To do so, bind Pi-hole’s
lighttpd only to the primary static IP address of the Raspberry Pi by adding the below to
# Bind pi.hole/admin to only the primary static ip server.bind = "192.168.0.100"
sudo systemctl restart lighttpd
eth0 with the below configuration to add a second static IP address:
auto eth0 allow-hotplug eth0 iface eth0 inet static address 192.168.0.100 # primary static ip, used by lighttpd (Pi-hole) netmask 255.255.255.0 gateway 192.168.0.1 dns-nameservers 127.0.0.1 iface eth0 inet static address 192.168.0.101 # second static ip netmask 255.255.255.0 dns-nameservers 127.0.0.1
The newer dhcpcd service doesn’t support multiple IP’s for one interface, so we disable it:
sudo systemctl stop dhcpcd sudo systemctl disable dhpcd
And switch to the old networking service instead:
sudo systemctl daemon-reload sudo systemctl restart networking
To resolve vhosts, add the file
And add the hosts with your new secondary IP address to
192.168.0.101 project.lan project
Restart dnsmasq and Pi-hole DNS:
sudo service dnsmasq force-reload pihole restartdns
Continue with setting up
nginx as usual.
Pi-hole has an API to disable and enable it quickly from other hosts, so that you don’t need to go through the web interface or SSH into the Raspberry Pi. For example you could add a browser bookmark or shell alias for:
PWHASH is the value of
enable to enable Pi-hole.
Combining Pi-hole with uBlock Origin
Pi-hole blocks unwanted content on a DNS level, so ads for example will never be loaded but will, depending on the websites CSS, leave their DOM footprint (the space they would normally be rendered in) behind. A client-side ad-blocker will remove them. The best I know is uBlock Origin.
IPSEC and Wireguard VPN are promising alternatives to OpenVPN. Algo VPN (PiVPN equivalent) simplifies their setup.