Pihole in HA mode

Pihole in HA mode

Pihole is the central point of resolving internal and external domains in my homelab. Running this on only one device is a classical SPOF so I run two separate instances on two physical devices in HA mode.

In my homelab I decided to use two spare Raspberry Pis doing all DNS resolving. Even my Fritzbox uses the Pihole devices as custom DNS server. The problem is, that the Fritzbox can only take one IP as DNS server server. There is no builtin logic running Pihole in a typical high availability (HA) setup like one Pihole goes down and the other one kicks in.

So even having two devices running Pihole, Fritzbox would only use one for resolving names, which is a single point of failure (SPOF).

Floating IP

The solution would be having a floating IP that jumps to the device, which can handle the current request. If both are up, there is a primary instance, and one or multiple secondary instances.

Fortunately there is keepalived which brings load balancing and high availability to Linux.

[…] keepalived runs a set of health checkers that watch each server pool and decide, in real time, whether a real server stays in the topology or drops out according to its health.

keepalived ships in most Linux distributions. I use Raspberry Pi OS Lite, the headless version without any desktop environment.

My current Pihole setup is:

  • Pihole 1: x.x.x.18
  • Pihole 2: x.x.x.19
  • Floating IP: x.x.x.53

On the Raspberry Pis I rolled out this configuration, with a different priority value, to define the primary and seconday instance.

 1global_defs {
 2  enable_script_security
 3  script_user root
 4}
 5
 6vrrp_script chk_pihole {
 7  // Replace with your actual IP
 8  script "/usr/bin/dig +short +time=1 +tries=1 pi.hole @x.x.x.19" 
 9  // Check each 2 seconds
10  interval 2 
11  // Require 2 consecutive failures mark node as down 
12  fall 2 
13  // Require 2 consecutive successes to mark as healthy again
14  rise 2 
15}
16
17vrrp_instance pihole {
18  state BACKUP
19  interface eth0
20  virtual_router_id 53
21  priority 100
22  advert_int 1
23
24  virtual_ipaddress {
25    x.x.x.53/24 // Replace with your actual IP
26  }
27
28  track_script {
29    chk_pihole
30  }
31}

In the healthcheck script you define how often a check can fail or should succeed to trigger failed or healthy states. In the example above, a check each 2 seconds with fall 2 means a failover after 4 seconds

Result

The only IP address that Fritzbox hands out to all my devices is x.x.x.53 which is a floating, load balanced IP what either one of my Raspberry Pis answers. I can update one Pi while the other one automatically serves all DNS requests.

This content was created on .
Enjoying codedge?

If I helped you in some way with my writing, a small contribution would support me. Your support keeps me creating!
Send a tip