Moderator edit:
This post contains scripts, or links to scripts, that are untested by the Pi-hole team. We encourage users to be creative, but we are unable to support any potential problems caused by running these scripts
Hello everyone,
this is my first post here and I hope I chose the right category. I wasn't sure if the topic is more suitable for general/customizing pihole or help/community or maybe somewhere completely different.
I've read a lot on raspberry pis lately and was looking for a nice project that would keep me occupied for some time, so I decided I wanted to set up a dual pihole HA setup. After reading a lot on it (also in this forum), I decided to go with two raspi zeros with USB2LAN adapters directly connected to my AVM Fritzbox 7590 and to use pihole, unbound, keepalived and gravitysync by @vmstan.
I know that it may be a little overkill, however, I needed a project to spend some time on...
I would like to show you my final setup with the instructions I wrote for myself and would really appreciate any kind of feedback, suggestions for improvement or security/performance concerns, as I'm really a beginner when it comes to network administration, DNS and linux.
Maybe it can even help another beginner to start their project.
1. Raspberry Pi OS: Installation and configuration (same for both raspis)
- Write Raspberry Pi OS Lite (bullseye) image on SD-card using Raspberry Pi Imager or any other suitable tool
- Create
ssh
file on the SD-card to enable ssh access to the raspi - Insert SD-card into raspi and boot up
- Check IP adress in the router and assign a static IP
- ssh into the raspi via Windows Powershell or putty using
ssh pi@xxx.xxx.xxx.xxx
where xxx.xxx.xxx.xxx is the ip adress of the raspi - Open config with
sudo raspi-config
to change hostname, password, timezone and expand the filesystem. Reboot. - Update packages with
sudo apt update && sudo apt upgrade
2. Pihole: installation and configuration (same for both raspis)
Command from the official pihole documentation GitHub - pi-hole/pi-hole: A black hole for Internet advertisements
curl -sSL https://install.pi-hole.net | bash
- Use standard values during installation
- Log into the pihole web userinterface with
http://xxx.xxx.xxx.xxx/admin
and go to Groupmanagement -> Adlists and add adlists (good lists for example under https://firebog.net/). You only need to do this for your primary raspi/pihole, because we will sync the lists with the secondary raspi/pihole later on.
3. Unbound: installation and configuration (same for both raspis)
Follow the official installation instructions from the pihole documentation unbound - Pi-hole documentation
- Install unbound with
sudo apt install unbound
- Open unbound config with
sudo nano /etc/unbound/unbound.conf.d/pi-hole.conf
and insert config from the documentation - If you use Raspberry Pi OS bullseye you need to open
sudo nano /etc/resolvconf.conf
and comment out the line starting withunbound_conf
and delete the resolvconf_resolver.conf withsudo rm /etc/unbound/unbound.conf.d/resolvconf_resolvers.conf
. Further information on this topic can be found here: https://discourse.pi-hole.net/t/warning-raspbian-october-2021-release-bullseye-unbound - Restart unbound with new config using
sudo systemctl restart unbound
- Check that unbound works correctly with
dig pi-hole.net @127.0.0.1 -p 5335
,dig sigfail.verteiltesysteme.net @127.0.0.1 -p 5335
anddig sigok.verteiltesysteme.net @127.0.0.1 -p 5335
which should return NOERROR, SERVFAIL and NOERROR respectively - Log into the pihole web userinterface with
http://xxx.xxx.xxx.xxx/admin
and go to Settings -> DNS to unselect the standard DNS servers and insert127.0.0.1#5335
in Custom DNS 1 (IPv4)
4. gravitysync: Installation and configuration
Instructions from official installation instructions GitHub - vmstan/gravity-sync: 💫 The easy way to synchronize the DNS configuration of two Pi-hole 5.x instances.
For the primary raspi/pihole:
- Install gravitysync using
export GS_INSTALL=primary && curl -sSL https://gravity.vmstan.com | bash
For the secondary raspi/pihole:
- Install gravitysync using
export GS_INSTALL=secondary && curl -sSL https://gravity.vmstan.com | bash
and when asked enter password of secondary raspi, IP-adress of primary raspi, username of primary raspi and password of primary raspi - Go to gravitsync folder with
cd ./gravity-sync
and check if gravitysync is working correctly with./gravity-sync.sh compare
- Pull databases from primary raspi/pihole with
./gravity-sync.sh pull
- Activate automatic sync with
./gravity-sync.sh automate
and define the synchronization frequency when asked
5. postfix: Installation and configuration (same for both raspis)
In this setup postfix is used with a gmail account to allow keepalived (see 6.) to send mails if one of the raspis/piholes goes down and the other one takes over. There are probably a lot of other option to do this.
- Install postfix and some sasl package with
sudo apt install postfix libsasl2-modules
and select "Internet Site" when asked during installation - Open postfix config with
sudo nano /etc/postfix/main.cf
and changerelayhost =
torelayhost = [smtp.gmail.com]:587
andinet_interfaces = all
toinet_interfaces = loopback-only
- Add the following lines at the bottom of the config
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_tls_security_level = encrypt
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
- Create the file containing the login data for gmail with
sudo nano /etc/postfix/sasl_passwd
and insert
[smtp.gmail.com]:587 USERNAME@gmail.com:APPPASSWORD
where USERNAME is the gmail username and APPPASSWORD is the app password you can create in the gmail web interface under account settings
- Create a .db file out of the login data file, that postfix needs for some reason with
sudo postmap /etc/postfix/sasl_passwd
- Secure the files by restricting access as the paswords are written in the files in plain text using
sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
- Restart postfix service with new config using
sudo systemctl restart postfix
6. keepalived: Installation and configuration
On primary raspi/pihole:
- Install keepalived with
sudo apt install keepalived
- Open config with
sudo nano /etc/keepalived/keepalived.conf
and insert
global_defs {
router_id HOSTNAME #HOSTNAME: hostname of primary pihole
notification_email {
USERNAME@gmail.com #USERNAME: gmail-username
}
smtp_server localhost
smtp_connect_timeout 30
}
vrrp_track_process track_pihole {
process pihole-FTL
weight 50
}
vrrp_instance pihole1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
smtp_alert
unicast_src_ip PRIMARY-PIHOLE-IPADRESS #PRIMARY-PIHOLE-IPADRESS: xxx.xxx.xxx.xxx
unicast_peer {
SECONDARY-PIHOLE-IPADRESS #SECONDARY-PIHOLE-IPADRESS: xxx.xxx.xxx.xxx
}
authentication {
auth_type PASS
auth_pass 8-CHARACTER-PASSWORD #8-CHARACTER-PASSWORD: alphanumerical password with max. 8 chars
}
virtual_ipaddress {
VIRTUAL-IPADRESS #VIRTUAL-IPADRESS: xxx.xxx.xxx.xxx/24
}
track_process {
track_pihole
}
}
- Enable autostart of keepalived service with
sudo systemctl enable --now keepalived
and restart keepalived withsudo systemctl restart keepalived
On secondary raspi/pihole:
- Install keepalived with
sudo apt install keepalived
- Open config with
sudo nano /etc/keepalived/keepalived.conf
and insert
global_defs {
router_id HOSTNAME #HOSTNAME: hostname of primary pihole
notification_email {
USERNAME@gmail.com #USERNAME: gmail-username
}
smtp_server localhost
smtp_connect_timeout 30
}
vrrp_track_process track_pihole {
process pihole-FTL
weight 50
}
vrrp_instance pihole2 {
state BACKUP
interface eth0
virtual_router_id 51
priority 90
advert_int 1
smtp_alert
unicast_src_ip Secondary-PIHOLE-IPADRESS #SECONDARY-PIHOLE-IPADRESS: xxx.xxx.xxx.xxx
unicast_peer {
PRIMARY-PIHOLE-IPADRESS #PRIMARY-PIHOLE-IPADRESS: xxx.xxx.xxx.xxx
}
authentication {
auth_type PASS
auth_pass 8-CHARACTER-PASSWORD #8-CHARACTER-PASSWORD: alphanumerical password with max. 8 chars
}
virtual_ipaddress {
VIRTUAL-IPADRESS #VIRTUAL-IPADRESS: xxx.xxx.xxx.xxx/24
}
track_process {
track_pihole
}
}
- Enable autostart of keepalived service with
sudo systemctl enable --now keepalived
and restart keepalived withsudo systemctl restart keepalived
That's it! Just define the virtual IP-adress as DNS server in your router. Pihole, unbound and gravitysync work fine so far. But keepalived only switches to the secondary pihole if the primary pihole looses network connection or powers of. The vrrp_track_process is not working, unfortunately. If I stop the pihole DNS service on the primary pihole, keepalived will not switch to the secondary pihole. I'm still working on that. Maybe someone here has an idea how to implement this functionality.
Thanks in advance for reading all of this and any feedback you can offer.