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 3and 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 keepalivedDebian/Ubuntu
sudo apt update && sudo apt install -y keepalived2) 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 --systemFirewall rules (allow VRRP protocol 112)
firewalld
sudo firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'
sudo firewall-cmd --reloadnftables (example)
sudo nft add rule inet filter input ip protocol vrrp accept
# persist ruleset
sudo nft list ruleset | sudotee /etc/nftables.conf3) 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,authenticationandvirtual_ipaddressmust match across nodes.- MASTER’s
prioritymust 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 -f5) 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 keepalivedNow check the BACKUP:
ip a show dev eth0 | grep 10.0.0.100- Start MASTER again (if
nopreemptis not set, the VIP will return to MASTER):
sudo systemctl start keepalivedOptional: 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
;;
*);;
esacsudo chmod +x /usr/local/bin/keepalived_notifyThen 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 3after 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=1and restart the app after VIP acquisition vianotify_master. - Avoid flapping: Use health checks (
vrrp_script) with sensible intervals, and considernopreemptto keep the VIP on the current healthy node until you plan a controlled failback. - Multiple VLANs: Use a distinct
virtual_router_idper broadcast domain to avoid VRID collisions. - Security: Use
auth_type PASSonly on trusted networks. For stronger integrity, consider VRRPv3 on IPv6 (different auth model) and/or host‑level controls.

