We'll be using Pi-hole installed in an Alpine container on Proxmox, but this should work on physical hosts with other base operating systems in using other hypervisors.
Firstly, we'll want to create our containers. As previously mentioned, we'll be using a Proxmox container and Alpine Linux v3.22. Because Pi-hole is very lightweight, we'll configure it with 2 CPUs, 128MB RAM, 256MB swap, and a 1GB HDD. Don't hesitate to assign more resources if required.
Pi-hole
Pi-hole is a caching DNS server used for network-wide advert blocking.
Install Pi-hole
Before we can install Pi-hole, we'll need to update our server and install Bash on all our hosts:
doas apk update
doas apk upgrade
doas apk add bashNow we can download and run the Pi-hole installer script on all our hosts:
wget -O basic-install.sh https://install.pi-hole.net
doas bash basic-install.shConfigure Pi-hole
On all our hosts, we'll need to configure Pi-hole to bind to eth0 and listen on all addresses. This can be done from the web UI.
If you didn't take note of the temporary password during installation, you can set a new password with the following command:
doas pihole setpassword [password]Entering no password will disable the password requirement (not recommended).
Keepalived
Keepalived is a service that creates virtual (or "floating") IPs that we give out to our clients.
Install Keepalived
Installing Keepalived on Alpine Linux is pretty straightforward. On all the hosts, we will run:
doas apk add keepalivedConfigure Keepalived
By default Alpine does not create the folder or configuration file, so we will need to create them ourselves. We will run the following on all out hosts:
doas mkdir /etc/keepalived
doas touch /etc/keepalived/keepalived.confpihole-1
On your pihole-1 host, in the /etc/keepalived/keepalived.conf file, add the following:
vrrp_sync_group VG1 {
VI_1
VI_2
}
vrrp_sync_group VG2 {
VI_3
VI_4
}
vrrp_script pihole-FTL {
script "killall -0 pihole-FTL"
interval 1
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd1!
}
virtual_ipaddress {
192.0.2.41
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_2 {
state MASTER
interface eth0
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd12
}
virtual_ipaddress {
2001:db8::41
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_3 {
state BACKUP
interface eth0
virtual_router_id 52
priority 50
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd3!
}
virtual_ipaddress {
192.0.2.42
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_4 {
state BACKUP
interface eth0
virtual_router_id 52
priority 50
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd4!
}
virtual_ipaddress {
2001:db8::42
}
track_script {
pihole-FTL
}
}pihole-2
On your pihole-2 host, in the /etc/keepalived/keepalived.conf file, add the following:
vrrp_sync_group VG1 {
VI_1
VI_2
}
vrrp_sync_group VG2 {
VI_3
VI_4
}
vrrp_script pihole-FTL {
script "killall -0 pihole-FTL"
interval 1
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 50
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd1!
}
virtual_ipaddress {
192.0.2.41
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_2 {
state BACKUP
interface eth0
virtual_router_id 51
priority 50
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd12
}
virtual_ipaddress {
2001:db8::41
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_3 {
state MASTER
interface eth0
virtual_router_id 52
priority 150
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd3!
}
virtual_ipaddress {
192.0.2.42
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_4 {
state MASTER
interface eth0
virtual_router_id 52
priority 150
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd4!
}
virtual_ipaddress {
2001:db8::42
}
track_script {
pihole-FTL
}
}pihole-3
On your pihole-3 host, in the /etc/keepalived/keepalived.conf file, add the following:
vrrp_sync_group VG1 {
VI_1
VI_2
}
vrrp_sync_group VG2 {
VI_3
VI_4
}
vrrp_script pihole-FTL {
script "killall -0 pihole-FTL"
interval 1
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd1!
}
virtual_ipaddress {
192.0.2.41
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_2 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd12
}
virtual_ipaddress {
2001:db8::41
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_3 {
state BACKUP
interface eth0
virtual_router_id 52
priority 100
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd3!
}
virtual_ipaddress {
192.0.2.42
}
track_script {
pihole-FTL
}
}
vrrp_instance VI_4 {
state BACKUP
interface eth0
virtual_router_id 52
priority 100
advert_int 1
authentication {
auth_type AH
auth_pass p@ssw0rd4!
}
virtual_ipaddress {
2001:db8::42
}
track_script {
pihole-FTL
}
}This will configure 4 virtual IPs, 2x IP4 and 2 IPv6, and group them so they fail together. They are configured so that no host will have both IP groups so long as at least 2 nodes are up. Additionally it ensures the pihole-FTL service is running.
NOTE: The IPs used above are special ranges meant for documentation. They should be adjusted for your environment.
Run Keepalived on startup
To run the keepalived service at startup, we'll run the following on all 3 hosts:
doas rc-update add keepalived default