IPVS and Keepalived for High Availability in Your Homelab
Running a single instance of any service means one thing: when it goes down, so does everything that depends on it. In a homelab, that might mean your DNS stops resolving, your reverse proxy goes offline, or your NAS becomes unreachable. Keepalived and IPVS solve this by giving you automatic failover and load balancing using tools that are already in the Linux kernel.
Photo by Xuancong Meng on Unsplash
Keepalived implements VRRP (Virtual Router Redundancy Protocol), which lets two or more machines share a single virtual IP address. One machine is the master and actively holds the IP. If it goes down, a backup takes over within seconds. IPVS (IP Virtual Server) is a kernel-level Layer 4 load balancer that distributes connections across multiple backend servers. Together, they give you production-grade high availability without any external dependencies.

Why Keepalived Over Other HA Solutions
Before diving in, it's worth understanding where Keepalived sits relative to other HA tools you might have heard of:
| Feature | Keepalived + IPVS | HAProxy | Corosync + Pacemaker | MetalLB (K8s) |
|---|---|---|---|---|
| Layer | L3/L4 (kernel) | L4/L7 (userspace) | Any (framework) | L2/L3 (K8s only) |
| Failover mechanism | VRRP | External (needs Keepalived) | Quorum-based | ARP/BGP |
| Load balancing | Yes (IPVS) | Yes (built-in) | Via managed resources | Yes |
| Config complexity | Low | Medium | High | Medium |
| Resource overhead | Minimal | Low | Moderate | Moderate |
| Best for | VIP failover + L4 LB | HTTP routing + L7 LB | Complex cluster resources | Kubernetes services |
Keepalived shines when you need a virtual IP that moves between hosts and kernel-level load balancing. It uses almost no resources — the daemon is tiny and IPVS runs in kernel space. For a homelab, this means you can add HA to a Raspberry Pi without worrying about overhead.
Installing Keepalived
On Debian/Ubuntu:
sudo apt update
sudo apt install -y keepalived ipvsadm
On Fedora/RHEL:
sudo dnf install -y keepalived ipvsadm
The ipvsadm package provides the command-line tool for inspecting and managing IPVS rules. Keepalived manages IPVS automatically through its configuration, but ipvsadm is invaluable for debugging.
Enable IP forwarding, which is required for IPVS to route traffic:
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-ipvs.conf
echo 'net.ipv4.ip_nonlocal_bind = 1' | sudo tee -a /etc/sysctl.d/99-ipvs.conf
sudo sysctl --system
The ip_nonlocal_bind setting allows services to bind to the virtual IP even when the local machine isn't the current VRRP master — important for services that start before failover occurs.
Understanding VRRP
VRRP works by having a group of routers (or servers) share a virtual IP. One is elected the master based on priority, and it periodically sends VRRP advertisements to the group. If the backup nodes stop hearing advertisements, the highest-priority backup promotes itself to master and takes over the virtual IP.
Key concepts:
- Virtual Router ID (VRID) — Identifies the VRRP group. All nodes sharing a VIP must use the same VRID. Values 1-255, must be unique on your network segment.
- Priority — Determines which node becomes master. Higher priority wins. Values 1-254 (255 is reserved).
- Advertisement interval — How frequently the master sends heartbeats. Default is 1 second.
- Preemption — When a higher-priority node comes back online, should it reclaim master? Usually yes, but you can disable this.
Like what you're reading? Subscribe to HomeLab Starter — free weekly guides in your inbox.
Basic VRRP Failover Configuration
Let's set up a virtual IP shared between two servers. This is the foundation for everything else.
Network layout:
- Server 1 (primary):
192.168.1.10 - Server 2 (backup):
192.168.1.11 - Virtual IP:
192.168.1.100
Server 1 (Master) — /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass homelabHA
}
virtual_ipaddress {
192.168.1.100/24
}
}
Server 2 (Backup) — /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass homelabHA
}
virtual_ipaddress {
192.168.1.100/24
}
}
Start keepalived on both:
sudo systemctl enable --now keepalived
Verify the virtual IP is on Server 1:
ip addr show eth0
You should see 192.168.1.100/24 listed as a secondary address. Now stop keepalived on Server 1 and watch Server 2 pick up the IP within about 3 seconds.
Adding Health Checks with VRRP Scripts
A virtual IP that only fails over when the whole machine goes down isn't enough. You want it to fail over when the service goes down too. Keepalived supports health check scripts that adjust the priority dynamically.
vrrp_script check_nginx {
script "/usr/bin/curl -sf http://localhost:80/ > /dev/null"
interval 2
weight -20
fall 3
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass homelabHA
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_nginx
}
}
When the check_nginx script fails 3 times in a row (fall 3), Keepalived subtracts 20 from the priority. If Server 1's priority drops from 100 to 80, Server 2 at priority 90 becomes the new master. When the script passes twice (rise 2), the priority is restored and Server 1 preempts back to master.
Common health check patterns:
# Check if a process is running
/usr/bin/pgrep -x nginx
# Check an HTTP endpoint
/usr/bin/curl -sf http://localhost:8080/health
# Check a TCP port
/usr/bin/nc -z localhost 5432
# Check if a file exists (maintenance mode)
/usr/bin/test ! -f /tmp/keepalived-maintenance
Load Balancing with IPVS
VRRP gives you failover. IPVS gives you load balancing. Keepalived manages both in a single configuration.
IPVS runs in the Linux kernel and supports three forwarding modes:
- NAT — The load balancer rewrites packet source/destination. Simple but the LB handles all return traffic.
- Direct Routing (DR) — The LB only handles incoming packets; return traffic goes directly from the real server to the client. Best performance, but requires all servers on the same L2 segment.
- IP Tunneling (TUN) — Like DR but works across subnets using IP-in-IP encapsulation.
For a homelab on a single subnet, DR mode is the best choice — it's fast and puts minimal load on the balancer.
IPVS Configuration Example
Here's a full configuration that provides a highly available, load-balanced web service:
vrrp_instance VI_WEB {
state MASTER
interface eth0
virtual_router_id 52
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass webHA123
}
virtual_ipaddress {
192.168.1.200/24
}
}
virtual_server 192.168.1.200 80 {
delay_loop 6
lb_algo rr
lb_kind DR
persistence_timeout 300
protocol TCP
real_server 192.168.1.21 80 {
weight 1
TCP_CHECK {
connect_timeout 3
connect_port 80
}
}
real_server 192.168.1.22 80 {
weight 1
TCP_CHECK {
connect_timeout 3
connect_port 80
}
}
real_server 192.168.1.23 80 {
weight 1
HTTP_GET {
url {
path /health
status_code 200
}
connect_timeout 3
retry 3
}
}
}
IPVS scheduling algorithms:
| Algorithm | Code | Best for |
|---|---|---|
| Round Robin | rr |
Equal servers, stateless services |
| Weighted Round Robin | wrr |
Mixed hardware (give faster servers more traffic) |
| Least Connections | lc |
Long-lived connections, varying request durations |
| Weighted Least Connections | wlc |
Mixed hardware with long-lived connections |
| Source Hashing | sh |
Sticky sessions without cookies |
For most homelab use cases, rr (round robin) or wlc (weighted least connections) work well.
Direct Routing Setup on Real Servers
When using DR mode, each real server needs to be configured to accept traffic for the virtual IP without responding to ARP requests for it. This prevents ARP conflicts — only the load balancer should answer ARP for the VIP.
On each real server:
# Add the VIP to the loopback interface
sudo ip addr add 192.168.1.200/32 dev lo
# Suppress ARP responses for the VIP
echo 1 | sudo tee /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 | sudo tee /proc/sys/net/ipv4/conf/all/arp_announce
Make these persistent by adding to /etc/sysctl.d/99-ipvs-dr.conf:
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
Practical Homelab HA Scenarios
HA DNS (Pi-hole / AdGuard Home)
Run two Pi-hole instances with Keepalived sharing a VIP. Point your DHCP server at the VIP instead of individual Pi-hole IPs:
vrrp_script check_pihole {
script "/usr/bin/dig +short @127.0.0.1 google.com > /dev/null 2>&1"
interval 5
weight -30
fall 3
rise 2
}
vrrp_instance VI_DNS {
state MASTER
interface eth0
virtual_router_id 53
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass dnsHA
}
virtual_ipaddress {
192.168.1.53/24
}
track_script {
check_pihole
}
}
HA Reverse Proxy
If you run Nginx or Caddy as your reverse proxy, putting Keepalived in front of two instances ensures your entire web stack stays up even if one proxy server fails.
HA Database (PostgreSQL)
Combine Keepalived with PostgreSQL streaming replication. The health check script verifies the local PostgreSQL is in read-write mode (primary), and if it fails, the VIP moves to the standby server. You'll need a promotion script in the notify_master hook to promote the standby automatically.
Monitoring IPVS
Use ipvsadm to inspect the current state:
# Show all virtual services and real servers
sudo ipvsadm -Ln
# Show connection statistics
sudo ipvsadm -Ln --stats
# Show rate information
sudo ipvsadm -Ln --rate
Keepalived also logs to syslog. Watch for failover events:
journalctl -u keepalived -f
You'll see messages like Entering MASTER STATE and Entering BACKUP STATE during transitions.
Troubleshooting
VIP not appearing: Check that virtual_router_id matches on all nodes and that no other VRRP instance on your network uses the same VRID. Also verify your firewall allows VRRP traffic (protocol 112).
Split brain (both nodes claim master): This usually means VRRP advertisements aren't reaching the backup. Check that multicast (or unicast, if configured) traffic isn't blocked. Switches with IGMP snooping can sometimes drop VRRP multicast.
IPVS not distributing traffic: Verify with ipvsadm -Ln that real servers show up and have non-zero connection counts. For DR mode, confirm the ARP settings on real servers and that the VIP is on loopback.
Firewall rules: Allow VRRP and the load-balanced ports:
# Allow VRRP (protocol 112)
sudo firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
# Allow the service port
sudo firewall-cmd --add-port=80/tcp --permanent
sudo firewall-cmd --reload
Next Steps
Once you have basic VRRP and IPVS running, consider adding notification scripts (notify_master, notify_backup, notify_fault) to trigger alerts through ntfy or Gotify when failovers happen. You can also combine Keepalived with HAProxy — use Keepalived for VIP failover and HAProxy for L7 routing, giving you the best of both worlds. For more complex setups with three or more nodes, look into unicast VRRP configuration to avoid multicast issues on certain network switches.
