PiHole - Add KeepAlive on two Pi's
Setting up keepalived for dual Pi-holes requires installing the package on both machines, writing a short configuration file on each, and pointing your network/AD DNS forwarder to the shared Virtual IP (VIP).
Prerequisites & Example Values
Check your network interface name using ip a (usually eth0 for wired or wlan0 for Wi-Fi).
-
Pi-hole A (Primary):
192.168.1.10(Interface:eth0) -
Pi-hole B (Secondary):
192.168.1.11(Interface:eth0) -
Shared Virtual IP (VIP):
192.168.1.99(Choose an unused static IP outside your DHCP range)
Step 1: Install keepalived on Both Pi-holes
Run the following commands on both Pi-hole servers:
sudo apt update
sudo apt install -y keepalived
Allow the Linux kernel to bind to non-local IP addresses (needed so Pi-hole can bind to the VIP even when it's not the active master):
echo "net.ipv4.ip_nonlocal_bind=1" | sudo tee -a /etc/sysctl.d/99-keepalived.conf
sudo sysctl --system
Step 2: Configure Pi-hole A (Primary / MASTER)
Create the configuration file on Pi-hole A:
sudo nano /etc/keepalived/keepalived.conf
Paste the following configuration:
vrrp_script check_pihole {
# Verify Pi-hole DNS service is answering queries locally
script "dig +short +time=1 +tries=1 @127.0.0.1 google.com > /dev/null 2>&1"
interval 2
weight -20
}
vrrp_instance VI_PIHOLE {
state MASTER
interface eth0 # Replace with your interface if different (e.g., wlan0)
virtual_router_id 51 # Must be identical on both Pis (1-255)
priority 100 # Higher priority = primary holder of VIP
advert_int 1
authentication {
auth_type PASS
auth_pass SecretPass123 # Must match on both Pis (max 8 chars)
}
virtual_ipaddress {
192.168.1.99/24 # Your shared VIP
}
track_script {
check_pihole
}
}
Save and exit (Ctrl+O, Enter, Ctrl+X).
Step 3: Configure Pi-hole B (Secondary / BACKUP)
Create the configuration file on Pi-hole B:
sudo nano /etc/keepalived/keepalived.conf
Paste the following configuration:
vrrp_script check_pihole {
script "dig +short +time=1 +tries=1 @127.0.0.1 google.com > /dev/null 2>&1"
interval 2
weight -20
}
vrrp_instance VI_PIHOLE {
state BACKUP
interface eth0 # Replace with your interface if different
virtual_router_id 51 # Must match Pi-hole A
priority 90 # Lower priority than Master
advert_int 1
authentication {
auth_type PASS
auth_pass SecretPass123 # Must match Pi-hole A
}
virtual_ipaddress {
192.168.1.99/24 # Same shared VIP
}
track_script {
check_pihole
}
}
Save and exit (Ctrl+O, Enter, Ctrl+X).
Step 4: Start and Enable the Services
Run these commands on both Pi-holes:
sudo systemctl enable keepalived
sudo systemctl restart keepalived
Step 5: Verify Failover Operation
-
Check which Pi holds the VIP: On Pi-hole A, run:
Baship a show eth0You should see
inet 192.168.1.99/24listed as a secondary IP on the interface. -
Test Failover:
-
Stop the service on Pi-hole A:
Bashsudo systemctl stop keepalived -
Run
ip a show eth0on Pi-hole B —192.168.1.99will immediately appear on Pi-hole B. -
Start
keepalivedback up on Pi-hole A:Bashsudo systemctl start keepalived -
Pi-hole A will reclaim the VIP because its priority (
100) is higher than Pi-hole B's (90).
-
-
Update Upstream Settings: Set the DNS forwarder address on your Active Directory DNS server, Synology NAS, or pfSense/DHCP scope to point strictly to the Virtual IP (
192.168.1.99).