VRRP with keepalived
Debian installs keepalived enabled but inactive: with no configuration file, the service doesn't start. The configuration is almost the same on both routers; only the router ID and the priority differ.
vrrp_instance STAFFshares 10.10.10.1 on the staff VLAN, andvrrp_instance WANshares 203.0.113.4 on the WAN. Each has a virtual router ID (10 and 20) that's the same on both routers, and must be unique on that network.- Priority: r1 has 150, r2 has 100, so r1 is the normal master. Both start as
BACKUPand let the priorities decide. advert_int 1: the master sends a VRRP advertisement every second. If the backup misses three, plus a short skew based on its priority, it takes over: about 3.6 seconds for r2.vrrp_sync_group OFFICEties the two instances together. Without it, a fault on one interface could leave the LAN address on one router and the WAN address on the other, and traffic would go in one door and find no way out.vrrp_script isp_reachableis a health check; more on it later.
The firewall needs one more rule on each router: VRRP is IP protocol 112, and it must be allowed in on both interfaces, or each router thinks the other is dead.
After starting keepalived on both routers, r1's log shows both instances, synchronised, entering MASTER, and it now holds 10.10.10.1 and 203.0.113.4 alongside its own addresses. r2 enters BACKUP. The staff PC's default route points at 10.10.10.1, and traffic flows. On the staff VLAN, tcpdump shows r1's advertisements to the multicast address 224.0.0.18: virtual router 10, priority 150, every second.
root@r1:~# cat /etc/debian_version; dpkg-query -W keepalived conntrackd nftables; uname -r
13.7
conntrackd 1:1.4.8-2+b1
keepalived 1:2.3.3-1
nftables 1.1.3-1
7.0.14-linuxkit
root@r1:~# systemctl is-active keepalived conntrackd; ls /etc/keepalived/
inactive
active
keepalived.conf.sample
keepalived.config-opts- Lines 3–5: keepalived, conntrackd and nftables from Debian 13.
- Lines 8–10: keepalived is installed but inactive: there's no configuration yet. conntrackd runs in its default statistics mode.
# /etc/keepalived/keepalived.conf on r1
global_defs {
router_id r1
enable_script_security
script_user root
}
# Is the ISP reachable from here? Two failed pings in a row and this router steps down.
vrrp_script isp_reachable {
script "/usr/bin/ping -c 1 -W 1 203.0.113.1"
interval 2
fall 2
rise 2
}
# Both addresses move together: a router that holds one must hold the other.
vrrp_sync_group OFFICE {
group {
STAFF
WAN
}
}
vrrp_instance STAFF {
state BACKUP
interface staff
virtual_router_id 10
priority 150
advert_int 1
virtual_ipaddress {
10.10.10.1/24
}
track_script {
isp_reachable
}
}
vrrp_instance WAN {
state BACKUP
interface eth0
virtual_router_id 20
priority 150
advert_int 1
virtual_ipaddress {
203.0.113.4/24
}
}- Line 3: The only differences on r2: its name and its priority (100).
- Lines 9–14: A health check: can this router reach the ISP?
- Lines 17–22: Both addresses move together.
- Lines 24–36: The staff gateway, 10.10.10.1, on VLAN 10, with the health check attached.
- Lines 38–47: The shared public address, 203.0.113.4.
root@r1:~# cp keepalived.conf /etc/keepalived/ && systemctl restart keepalived
root@r2:~# cp keepalived.conf /etc/keepalived/ && systemctl restart keepalived
root@r1:~# journalctl -u keepalived --no-pager -o cat | grep -E "STATE|Syncing"; ip -br -4 addr show dev staff; ip -br -4 addr show dev eth0
(STAFF) Entering BACKUP STATE
VRRP_Group(OFFICE) Syncing instances to BACKUP state
(WAN) Entering BACKUP STATE
(WAN) Entering MASTER STATE
VRRP_Group(OFFICE) Syncing instances to MASTER state
(STAFF) Entering MASTER STATE
staff@eth1 UP 10.10.10.2/24 10.10.10.1/24
eth0@if5551 UP 203.0.113.2/24 203.0.113.4/24
root@r2:~# journalctl -u keepalived --no-pager -o cat | grep -E "STATE|Syncing"; ip -br -4 addr show dev staff; ip -br -4 addr show dev eth0
(STAFF) Entering BACKUP STATE
VRRP_Group(OFFICE) Syncing instances to BACKUP state
(WAN) Entering BACKUP STATE
staff@eth1 UP 10.10.10.3/24
eth0@if5556 UP 203.0.113.3/24
root@staff:~# ip route; ping -c 2 -W 1 198.51.100.10 | tail -2
default via 10.10.10.1 dev eth0.10
10.10.10.0/24 dev eth0.10 proto kernel scope link src 10.10.10.20
2 packets transmitted, 2 received, 0% packet loss, time 1060ms
rtt min/avg/max/mdev = 0.116/0.152/0.188/0.036 ms
root@r1:~# tcpdump -lnni staff -c 2 vrrp 2>/dev/null
22:47:21.253436 IP 10.10.10.2 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 150, authtype none, intvl 1s, length 20
22:47:21.253443 IP 10.10.10.2 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 150, authtype none, intvl 1s, length 20- Lines 6–11: r1: both instances synchronised to MASTER.
- Lines 12–13: r1 now holds 10.10.10.1 and 203.0.113.4 as well as its own addresses.
- Lines 16–20: r2: BACKUP, own addresses only.
- Lines 22–26: The staff PC's gateway is the shared address, and traffic flows.
- Lines 28–30: r1's advertisements: virtual router 10, priority 150, every second.
Check your understanding
Why do the two instances sit in one vrrp_sync_group?
- So the LAN and WAN addresses are always on the same router; otherwise traffic could go in one router and find no way out.
- Because keepalived only allows one instance per router.
- To share the connection table.
- To make the routers share a priority.