Shut your Pi-hole!
There are a bunch of posts similar to this one but I couldn’t find one that brought all of these elements together, so, here is my brain dump on how to install Pi-hole with Unbound and PiVPN.
Pi-hole With Unbound and PiVPN – Update Everything
Ensure that the system is up to date:
sudo apt update && sudo apt upgrade
First, install Pi-hole
The Pi-hole ® is a DNS sinkhole that protects your devices from unwanted content, without installing any client-side software.
One-Step Automated Install
Start the process by typing the following in a Terminal:
curl -sSL https://install.pi-hole.net | bash
Then, accept all the defaults.
Either write down the generated password or change the password later by running ‘pihole -a -p
‘ in a Terminal.
Add Pi-hole rules to ufw Firewall
Pi-hole needs to both listen to and sometimes talk to the outside world.
I use ‘ufw’ or ‘ Uncomplicated Firewall ‘ so I need to allow traffic to the Pi-hole ports:
sudo ufw allow 53/tcp comment "Pi-hole Port 53 tcp traffic"
sudo ufw allow 53/udp comment "Pi-hole Port 53 udp traffic"
sudo ufw allow 67/tcp comment "Pi-hole Port 67 tcp traffic"
sudo ufw allow 67/udp comment "Pi-hole Port 67 udp traffic"
Also add IPv6 Rules (include above IPv4 rules)
sudo ufw allow 546:547/udp comment "Pi-hole DHCP traffic"
To delete old rules
sudo ufw status verbose
sudo ufw status numbered
sudo ufw delete number_of_rule
DHCP on the router can now be turned off.
Pi-hole Blocklists
Generally the first step is to think about what you want to block on your network.
Then, implement lists that satisfy the above.
This is a good overview of blocklists:
https://www.avoidthehack.com/best-pihole-blocklists
My Blocklists
I subscribe to the ‘less is more’ ethos and have a few high quality curated lists rather than blocking millions of URLs.
https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn/hosts
https://raw.githubusercontent.com/EnergizedProtection/EnergizedBlu/master/energized/blu.txt
https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
https://phishing.army/download/phishing_army_blocklist_extended.txt
Use nginx over lighttpd
I already have a web server up and running (you are reading this because of it) so I don’t really need lighttpd running as well.
sudo systemctl disable lighttpd
sudo apt-get purge --auto-remove lighttpd
sudo systemctl restart nginx
sudo rm
/var/www/html``/index.lighttpd.html
Or, use both and edit lighttpd.conf
and change the listening port:
sudo nano /etc/lighttpd/lighttpd.conf
From:
server.port = 80
To:
server.port = 8080
Flush the Pi-hole logs and db using cron
I like bash scripts, so I obviously wrote one to:
- Flush stale ‘neighbouring’ leases
- Flush current leases
- Remove old lists
- Remove both the query database and the log (long term storage)
- Remove the dnsmasq log (short term storage)
- Update Gravity
- Restart DNS
Pi-hole probably has a way to do all of this somewhere but I just like writing scripts.
Firstly, create the script:
sudo nano /etc/init.d/flush_pihole.sh
#!/bin/bash
clear
# Stop the pihole service
echo ""
echo -e "\e[1;33mStop the pihole service...\e[0m"
service pihole-FTL stop
echo -e "\e[32mDone\e[0m"
# Flush stale 'neighbouring' leases
echo ""
echo -e "\e[1;33mFlush stale 'neighbouring' leases...\e[0m"
ip neigh flush nud stale
echo -e "\e[32mDone\e[0m"
# Flush current leases
echo ""
echo -e "\e[1;33mFlush current leases...\e[0m"
rm /etc/pihole/dhcp.leases
echo -e "\e[32mDone\e[0m"
# Remove old lists
echo ""
echo -e "\e[1;33mRemove old lists...\e[0m"
rm /etc/pihole/list.*
echo -e "\e[32mDone\e[0m"
# Remove the query database and log (long term storage)
echo ""
echo -e "\e[1;33mRemove the query database and log (long term storage)...\e[0m"
rm /etc/pihole/pihole-FTL.db
rm /etc/pihole/pihole-FTL.log
echo -e "\e[32mDone\e[0m"
# Remove the dnsmasq log (short term storage)
echo ""
echo -e "\e[1;33mRemove the dnsmasq log (short term storage)...\e[0m"
rm /var/log/pihole.log
echo -e "\e[32mDone\e[0m"
# Start the pihole service
echo ""
echo -e "\e[1;33mStart the pihole service...\e[0m"
service pihole-FTL start
echo -e "\e[32mDone\e[0m"
# Update Gravity
echo ""
echo -e "\e[1;33mUpdate Gravity...\e[0m"
pihole -g
echo -e "\e[32mDone\e[0m"
# Restart DNS
echo ""
echo -e "\e[1;33mRestart DNS...\e[0m"
pihole restartdns
echo -e "\e[32mDone\e[0m"
# Is pihole running
echo -e "\e[1;33mIs pihole running...\e[0m"
systemctl status --no-pager pihole-FTL
echo -e "\e[32mDone\e[0m"
echo ""
Then, give the file the correct permissions:
sudo chmod +x /etc/init.d/flush_pihole.sh
Finally, add it to root cron and set it to run daily at midnight:
sudo crontab -e
#
# Flush the Pi-hole logs & db also update Gravity daily at midnight
0 0 * * * sh /etc/init.d/flush_pihole.sh
#
Then, install Unbound
Unbound is a validating, recursive, caching DNS resolver.
I followed the Pi-hole Unbound guide, and started with:
sudo apt install unbound
Configure Unbound
In a Terminal, type the following:
sudo nano /etc/unbound/unbound.conf.d/pi-hole.conf
This will:
- Listen only for queries from the local Pi-hole installation (on port 5335)
- Listen for both UDP and TCP requests
- Verify DNSSEC signatures, discarding BOGUS domains
- Apply a few security and privacy tricks
server:
# If no logfile is specified, syslog is used
# logfile: "/var/log/unbound/unbound.log"
verbosity: 0
interface: 127.0.0.1
port: 5335
do-ip4: yes
do-udp: yes
do-tcp: yes
# May be set to yes if you have IPv6 connectivity
do-ip6: no
# You want to leave this to no unless you have *native* IPv6. With 6to4 and
# Terredo tunnels your web browser should favor IPv4 for the same reasons
prefer-ip6: no
# Use this only when you downloaded the list of primary root servers!
# If you use the default dns-root-data package, unbound will find it automatically
#root-hints: "/var/lib/unbound/root.hints"
# Trust glue only if it is within the server's authority
harden-glue: yes
# Require DNSSEC data for trust-anchored zones, if such data is absent, the zone becomes BOGUS
harden-dnssec-stripped: yes
# Don't use Capitalization randomization as it known to cause DNSSEC issues sometimes
# see https://discourse.pi-hole.net/t/unbound-stubby-or-dnscrypt-proxy/9378 for further details
use-caps-for-id: no
# Reduce EDNS reassembly buffer size.
# IP fragmentation is unreliable on the Internet today, and can cause
# transmission failures when large DNS messages are sent via UDP. Even
# when fragmentation does work, it may not be secure; it is theoretically
# possible to spoof parts of a fragmented DNS message, without easy
# detection at the receiving end. Recently, there was an excellent study
# >>> Defragmenting DNS - Determining the optimal maximum UDP response size for DNS <<<
# by Axel Koolhaas, and Tjeerd Slokker (https://indico.dns-oarc.net/event/36/contributions/776/)
# in collaboration with NLnet Labs explored DNS using real world data from the
# the RIPE Atlas probes and the researchers suggested different values for
# IPv4 and IPv6 and in different scenarios. They advise that servers should
# be configured to limit DNS messages sent over UDP to a size that will not
# trigger fragmentation on typical network links. DNS servers can switch
# from UDP to TCP when a DNS response is too big to fit in this limited
# buffer size. This value has also been suggested in DNS Flag Day 2020.
edns-buffer-size: 1232
# Perform prefetching of close to expired message cache entries
# This only applies to domains that have been frequently queried
prefetch: yes
# One thread should be sufficient, can be increased on beefy machines. In reality for most users running on small networks or on a single machine, it should be unnecessary to seek performance enhancement by increasing num-threads above 1.
num-threads: 1
# Ensure kernel buffer is large enough to not lose messages in traffic spikes
so-rcvbuf: 1m
# Ensure privacy of local IP ranges
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
Limit the packet size
sudo nano /etc/dnsmasq.d/99-edns.conf
edns-packet-max=1232
Restart Unbound
sudo service unbound restart
sudo service unbound status
Test validation
Type the following in a Terminal:
dig fail01.dnssec.works @127.0.0.1 -p 5335
This first command should give a status report of SERVFAIL and no IP address.
Then, type the following in a Terminal:
dig dnssec.works @127.0.0.1 -p 5335
This second command should give NOERROR plus an IP address.
Configure Pi-hole to use Unbound
Firstly, log in to the Pi-hole web interface:
http://your_server_ip/admin/login.php
Pi-hole Unbound DNS Settings
In Settings | DNS
First, Untick any existing Upstream DNS Servers.
Then, add the Unbound settings.
In Upstream DNS Servers | Custom 1 (IPv4)
Set to 127.0.0.1#5335
Disable resolvconf.conf
entry for unbound
The why is from here and is required for Debian Bullseye+ releases.
Firstly, check to see if the service is running:
systemctl is-active unbound-resolvconf.service
If it is, disable it:
sudo systemctl disable --now unbound-resolvconf.service
Then, restart Unbound:
sudo service unbound restart
sudo service unbound status
Then, install PiVPN
The simplest way to setup and manage a VPN,
designed for Raspberry Pi™.
One line install
curl -L https://install.pivpn.io | bash
Then, step through the screens, choosing:
User – Whatever_You_Want
VPN – WireGuard (or OpenVPN, the choice is yours)
Port – 51820
DNS – ‘Your_Public_IP’
unattended-upgrades – Yes
Remember to forward Port 51820 (UDP traffic) on the Router to the server.
Reboot and add Profiles
Firstly, start by adding a new client connection:
sudo pivpn add
Then, enter a name for the client.
Then, to generate a QR code that can be scanned from a mobile device:
sudo pivpn -qr
Check it’s all working
Firstly, in a Terminal, check the “last seen” entry by running the following:
sudo pivpn -c
Then, check the Pi-hole web interface under ‘Tools | Network‘ to see if the VPN gets filtered, there should be entries for:
Whatever_You_Want.pivpn
That’s how to install Pi-hole With Unbound and PiVPN.