Keepalived VRRP Configuration: Master/Backup on Linux (Step‑by‑Step)
High availability on bare‑metal or virtual servers doesn’t have to be complex. In this guide you’ll configure Keepalived with VRRP to provide a floating Virtual IP (VIP) that “moves” between two Linux nodes: one MASTER and one BACKUP. We’ll use unicast VRRP (works even when multicast is restricted) and add optional health checks, fast ARP convergence, and clean failover testing.
What you’ll build
- Two Linux servers sharing a single VIP.
- Server A is MASTER (higher priority), Server B is BACKUP.
- If the MASTER fails, the VIP moves to the BACKUP automatically.
- Optional: service‑aware failover (priority drops if your app is down), plus small hooks to start/stop services when a node becomes MASTER/BACKUP.
Reference topology (adjust to your network)
- Node A (MASTER preferred):
10.0.0.10
(interface:eth0
) - Node B (BACKUP):
10.0.0.11
(interface:eth0
) - VIP (IPv4):
10.0.0.100/24
- VRID:
51
(1–255; must be the same on both nodes)
You can run IPv6 too. For IPv6 addresses, switch to
vrrp_version 3
and use an IPv6 VIP (sample below).
Prerequisites
- Root or sudo access on both nodes.
- Internet access or install packages following this documentation.
- Matching network segment for the VIP and both nodes.
- Firewall allows protocol 112 (VRRP) between nodes.
1) Install Keepalived
RHEL/Rocky/Oracle Linux
sudo dnf install -y keepalived || sudo yum install -y keepalived
Debian/Ubuntu
sudo apt update && sudo apt install -y keepalived
2) Recommended network/sysctl settings
Enable binding to the VIP even when it’s not yet on the local node (useful if your app binds to the VIP):
echo "net.ipv4.ip_nonlocal_bind = 1" | sudotee /etc/sysctl.d/99-keepalived.conf
sudo sysctl --system
Firewall rules (allow VRRP protocol 112)
firewalld
sudo firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'
sudo firewall-cmd --reload
nftables (example)
sudo nft add rule inet filter input ip protocol vrrp accept
# persist ruleset
sudo nft list ruleset | sudotee /etc/nftables.conf
3) Keepalived configuration files
Edit /etc/keepalived/keepalived.conf
on both nodes as shown.
Node A (MASTER preferred) — /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface eth0
vrrp_version 2
virtual_router_id 51
priority 150
advert_int 1
# Unicast VRRP to avoid multicast requirements
unicast_src_ip 10.0.0.10
unicast_peer {
10.0.0.11
}
authentication {
auth_type PASS
auth_pass SuperSecreto123
}
virtual_ipaddress {
10.0.0.100/24 dev eth0 label eth0:1
}
# Faster neighbor convergence after failover
garp_master_delay 1
garp_master_repeat 5
# Optional: avoid automatic failback to MASTER when it returns
# nopreempt
# Optional service health check (example: nginx)
# vrrp_script chk_app {
# script "pidof nginx >/dev/null 2>&1"
# interval 2
# weight -30
# }
# track_script {
# chk_app
# }
# Optional hooks for service control on state changes
# notify_master "/usr/local/bin/keepalived_notify master"
# notify_backup "/usr/local/bin/keepalived_notify backup"
# notify_fault "/usr/local/bin/keepalived_notify fault"
}
Node B (BACKUP) — /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state BACKUP
interface eth0
vrrp_version 2
virtual_router_id 51
priority 100
advert_int 1
unicast_src_ip 10.0.0.11
unicast_peer {
10.0.0.10
}
authentication {
auth_type PASS
auth_pass SuperSecreto123
}
virtual_ipaddress {
10.0.0.100/24 dev eth0 label eth0:1
}
garp_master_delay 1
garp_master_repeat 5
# nopreempt # also here if you want to avoid failback
# vrrp_script chk_app {
# script "pidof nginx >/dev/null 2>&1"
# interval 2
# weight -30
# }
# track_script {
# chk_app
# }
}
Notes
virtual_router_id
,advert_int
,authentication
andvirtual_ipaddress
must match across nodes.- MASTER’s
priority
must be higher than BACKUP’s. Default tie‑breaker is the higher primary IP.- Add more VIPs by listing additional addresses in
virtual_ipaddress { … }
(one per line).
4) Enable and start the service
Run on both nodes:
sudo systemctl enable --now keepalived
sudo systemctl status keepalived --no-pager
# live logs
journalctl -u keepalived -f
5) Validate and test failover
- Confirm the VIP lives on the MASTER:
ip a show dev eth0 | grep 10.0.0.100
- From a third host, ping the VIP:
ping 10.0.0.100
- Force failover by stopping Keepalived on the MASTER:
sudo systemctl stop keepalived
Now check the BACKUP:
ip a show dev eth0 | grep 10.0.0.100
- Start MASTER again (if
nopreempt
is not set, the VIP will return to MASTER):
sudo systemctl start keepalived
Optional: service control hooks (notify script)
Create a small script to start/stop your app when the node gains/loses the VIP.
/usr/local/bin/keepalived_notify
:
#!/usr/bin/env bash
set-euo pipefail
STATE=${1:-}
case "$STATE" in
master)
systemctl start haproxy || true
;;
backup|fault)
systemctl stop haproxy || true
;;
*);;
esac
sudo chmod +x /usr/local/bin/keepalived_notify
Then uncomment the notify_*
lines in your keepalived.conf
.
Troubleshooting & hardening
- VIP doesn’t move / clients still hit old node: Increase gratuitous ARP:
garp_master_repeat 5
(already in the sample). You can also manually nudge neighbors:arping -U -I eth0 10.0.0.100 -c 3
after a switchover. - Firewall drops VRRP: Ensure protocol 112 is allowed between nodes (see rules above). If using routers/L3 firewalls between nodes, allow it there too.
- Service is up but traffic fails: If your app binds strictly to the VIP, make sure
net.ipv4.ip_nonlocal_bind=1
and restart the app after VIP acquisition vianotify_master
. - Avoid flapping: Use health checks (
vrrp_script
) with sensible intervals, and considernopreempt
to keep the VIP on the current healthy node until you plan a controlled failback. - Multiple VLANs: Use a distinct
virtual_router_id
per broadcast domain to avoid VRID collisions. - Security: Use
auth_type PASS
only on trusted networks. For stronger integrity, consider VRRPv3 on IPv6 (different auth model) and/or host‑level controls.