Keepalived and VRRP: Building High-Availability Failover for Linux Services
What Keepalived Solves
A single load balancer is a single point of failure. Keepalived uses VRRP (Virtual Router Redundancy Protocol) to share a virtual IP between two or more servers. The master node owns the VIP; if it fails, a backup takes over within seconds — transparently from the perspective of clients hitting the VIP.
This is the standard pattern for making Nginx, HAProxy, or any TCP service highly available without a hardware load balancer.
Installation
# RHEL/Rocky/AlmaLinux
sudo dnf install keepalived -y
# Ubuntu/Debian
sudo apt install keepalived -y
sudo systemctl enable keepalived
Basic VRRP Configuration
Master Node
Edit /etc/keepalived/keepalived.conf on the master:
global_defs {
router_id LB01 # unique name for this node
script_user root
enable_script_security
}
vrrp_instance VI_1 {
state MASTER
interface eth0 # NIC that carries the VIP
virtual_router_id 51 # must match on all nodes in the group (1-255)
priority 100 # higher = preferred; master should be highest
advert_int 1 # VRRP advertisement interval (seconds)
authentication {
auth_type PASS
auth_pass secretpass # shared secret between nodes
}
virtual_ipaddress {
192.168.1.100/24 dev eth0 # the virtual IP
}
}
Backup Node
Edit /etc/keepalived/keepalived.conf on the backup:
global_defs {
router_id LB02
script_user root
enable_script_security
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51 # must match master
priority 90 # lower than master
advert_int 1
authentication {
auth_type PASS
auth_pass secretpass
}
virtual_ipaddress {
192.168.1.100/24 dev eth0
}
}
Start on both nodes:
sudo systemctl start keepalived
Verify the VIP is assigned to the master:
ip addr show eth0
# You should see 192.168.1.100/24 on the master node
Failover Behavior
- Master broadcasts VRRP advertisements every
advert_intseconds - Backup listens; if it doesn't hear from master for 3×
advert_intseconds, it takes over - Backup claims the VIP (brings it up on its own interface)
- When master recovers, it reclaims the VIP (MASTER state + higher priority)
To prevent "flapping" (rapid failover/failback), set nopreempt on the backup config to prevent the master from taking back the VIP after recovery:
vrrp_instance VI_1 {
state BACKUP
nopreempt # don't preempt the current master on recovery
...
}
And change the master's state to BACKUP with higher priority — both nodes are BACKUP, but the one with higher priority wins initially.
Health Check Scripts
VRRP failover alone is based on network connectivity. For application-level failover, use vrrp_script to check if the service is actually working:
vrrp_script check_haproxy {
script "/usr/bin/pgrep haproxy" # returns 0 if haproxy is running
interval 2 # check every 2 seconds
weight -20 # subtract 20 from priority if fails
fall 2 # fail after 2 consecutive failures
rise 2 # recover after 2 consecutive successes
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass secretpass
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_haproxy
}
}
If HAProxy is down: priority drops from 100 to 80 (100 - 20). The backup at priority 90 wins and takes the VIP.
Custom Health Check Script
# /usr/local/bin/check_nginx.sh
#!/bin/bash
if curl -sf http://127.0.0.1/health > /dev/null 2>&1; then
exit 0 # healthy — script succeeds
else
exit 1 # unhealthy — triggers weight adjustment
fi
vrrp_script check_nginx {
script "/usr/local/bin/check_nginx.sh"
interval 3
weight -30
fall 2
rise 2
}
Make scripts executable:
sudo chmod +x /usr/local/bin/check_nginx.sh
Multiple VIPs / Active-Active
Run multiple VRRP instances for different VIPs — each can have a different master, achieving active-active load distribution:
# On LB01: master for VIP1, backup for VIP2
vrrp_instance VI_1 {
state MASTER
virtual_router_id 51
priority 100
virtual_ipaddress {
192.168.1.100/24
}
}
vrrp_instance VI_2 {
state BACKUP
virtual_router_id 52
priority 90
virtual_ipaddress {
192.168.1.101/24
}
}
# On LB02: backup for VIP1, master for VIP2
vrrp_instance VI_1 {
state BACKUP
virtual_router_id 51
priority 90
virtual_ipaddress {
192.168.1.100/24
}
}
vrrp_instance VI_2 {
state MASTER
virtual_router_id 52
priority 100
virtual_ipaddress {
192.168.1.101/24
}
}
DNS round-robin between both VIPs completes the active-active setup.
Notify Scripts
Run a script when state changes (e.g., send an alert):
vrrp_instance VI_1 {
...
notify_master "/usr/local/bin/notify.sh MASTER"
notify_backup "/usr/local/bin/notify.sh BACKUP"
notify_fault "/usr/local/bin/notify.sh FAULT"
}
# /usr/local/bin/notify.sh
#!/bin/bash
STATE=$1
echo "$(date): Keepalived state changed to $STATE on $(hostname)" >> /var/log/keepalived-state.log
# Add Slack/PagerDuty notification here
Monitoring and Troubleshooting
# Check Keepalived status
sudo systemctl status keepalived
# View logs
sudo journalctl -u keepalived -f
# Check current VIP assignment
ip addr show | grep "192.168.1.100"
# Monitor VRRP advertisements with tcpdump
sudo tcpdump -i eth0 vrrp
# Test failover: stop keepalived on master
sudo systemctl stop keepalived
# VIP should move to backup within ~3 seconds
# Verify from a client
ping 192.168.1.100 # should continue with minor blip during failover
Common Pitfalls
VIP not moving on failover: Check that virtual_router_id matches on both nodes and auth_pass is identical.
Both nodes claim MASTER: Network split-brain — VRRP advertisements aren't reaching the other node. Check firewall rules for VRRP (protocol 112, multicast 224.0.0.18):
# RHEL/Rocky
sudo firewall-cmd --permanent --add-protocol=vrrp
sudo firewall-cmd --reload
# Ubuntu (ufw)
sudo ufw allow proto vrrp
Health check not triggering failover: Ensure the script file is executable and returns a non-zero exit code on failure. Test manually: sudo /usr/local/bin/check_nginx.sh; echo $?
Keepalived requires privileges: With enable_script_security, scripts must be owned by root and not world-writable.
Was this article helpful?
Network & Traffic Engineer
Packets don't lie. I design and troubleshoot the network layer that everything else depends on — Nginx, Envoy, HAProxy, DNS, CDNs, and everything in between. If it touches a socket, it's my problem.
Related Articles
HAProxy + Keepalived: Production HA Load Balancer Setup
Step-by-step guide to building a highly available load balancer pair with HAProxy and Keepalived — covering the full stack from VIP configuration to health checks, stats, and SSL termination.
Keepalived VRRP: Automatic Failover for Load Balancers
Implement automatic failover for HAProxy and Nginx using Keepalived with VRRP — virtual IPs, health checks, and split-brain prevention.
Envoy Proxy: Architecture, xDS Configuration, and Getting Started
An introduction to Envoy Proxy's architecture — listeners, clusters, filters, and the xDS dynamic configuration API. Covers static configuration for standalone use and how Envoy fits into service meshes like Istio.
HAProxy Configuration Guide: TCP/HTTP Load Balancing, Health Checks, and SSL
A comprehensive HAProxy configuration guide covering frontends, backends, balance algorithms, active health checks, SSL termination, ACLs, rate limiting, and the runtime socket API.
Keepalived VRRP: Build a Highly Available Load Balancer Pair
Set up a highly available load balancer pair using Keepalived VRRP with a shared virtual IP that automatically fails over between two nodes.
Nginx Load Balancing: Round Robin, Least Conn, and IP Hash
Configure Nginx upstream load balancing with round robin, least connections, and IP hash strategies including health checks and failover.
More in Nginx
View all →Apache mod_proxy: Reverse Proxy, Load Balancing, and WebSocket Support
How to use Apache httpd as a reverse proxy with mod_proxy — proxying to backend services, load balancing across multiple upstreams, WebSocket proxying, and health check configuration.
Apache httpd: Virtual Hosts, SSL/TLS, and URL Rewriting in Production
How to configure Apache httpd for production use — name-based virtual hosts, SSL/TLS with Let's Encrypt, HTTP to HTTPS redirects, mod_rewrite rules, and performance tuning with MPM.
Envoy Traffic Management: Retries, Timeouts, Canary Deployments, and Rate Limiting
Advanced Envoy traffic management — configuring retries with exponential backoff, per-request timeouts, weighted canary routing, global rate limiting, and fault injection for resilience testing.
HAProxy Advanced: SSL Termination, SNI Routing, and mTLS
Advanced HAProxy SSL configuration — multi-domain SNI routing from a single frontend, mutual TLS (mTLS) for service-to-service authentication, certificate management, and OCSP stapling.