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).

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

  1. Check which Pi holds the VIP: On Pi-hole A, run:

    ip a show eth0
    

    You should see inet 192.168.1.99/24 listed as a secondary IP on the interface.

  2. Test Failover:

    • Stop the service on Pi-hole A:

      sudo systemctl stop keepalived
      
    • Run ip a show eth0 on Pi-hole B192.168.1.99 will immediately appear on Pi-hole B.

    • Start keepalived back up on Pi-hole A:

      sudo systemctl start keepalived
      
    • Pi-hole A will reclaim the VIP because its priority (100) is higher than Pi-hole B's (90).

  3. 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).


Revision #2
Created 11 August 2026 18:46:48 by Steve Ling
Updated 11 August 2026 23:06:52 by Steve Ling