When a router goes down, the network goes down. For homes, it's an annoyance. For businesses, it's lost revenue. Keepalived solves this by implementing VRRP (Virtual Router Redundancy Protocol) -- two or more routers share a virtual IP. If the master fails, the backup takes over in seconds.
I contributed Keepalived integration to OpenWrt across three areas: the core package improvements, a UCI configuration layer, and a LuCI web interface.
What Keepalived Does Link to heading
Keepalived runs on each router in the cluster. It continuously monitors the master router's health via VRRP advertisements. If the master stops sending them (hardware failure, network disconnect, process crash), the backup promotes itself to master and assumes the virtual IP. Client devices never know the difference.
Beyond basic failover, Keepalived supports:
- Multiple VRRP instances -- different virtual IPs for different subnets or services
- Priority-based election -- assign weights so the most capable router wins
- Preemption -- if a higher-priority router comes back online, it reclaims the master role
- Track interfaces -- demote a router's priority if a critical interface goes down
- Notification scripts -- trigger custom actions on state changes (send alerts, update DNS, adjust firewall rules)
UCI Configuration Layer Link to heading
OpenWrt's Unified Configuration Interface (UCI) keeps all service configuration in /etc/config/. I integrated Keepalived into this system so you don't have to hand-edit keepalived.conf.
A minimal UCI config for a two-router VRRP cluster:
config globals 'globals'
option alt_config_file "/tmp/keepalived/keepalived.conf"
option smtp_alert '0'
config vrrp_instance 'lan'
option interface 'lan'
option virtual_router_id '51'
option priority '100' # 100 = master, 50 = backup
option advert_int '1'
option virtual_ipaddress '192.168.1.1/24'
The key fields:
| Option | Purpose |
|---|---|
virtual_router_id | Unique ID shared by all routers in this VRRP group (0-255) |
priority | Higher value wins the election |
advert_int | How often (seconds) the master sends heartbeat advertisements |
virtual_ipaddress | The floating IP clients connect to -- must be the same on all routers |
For tracking interfaces -- if WAN goes down, this router should not be master:
config vrrp_instance 'lan'
...
list track_interface 'wan'
option track_interface_priority '20'
This lowers the priority by 20 if WAN fails, causing a failover even if the router itself is still running.
High-Availability File Sync Link to heading
VRRP handles IP failover, but what about state? If the master handles DHCP leases, VPN tunnels, or firewall connection tracking, the backup needs that data to take over seamlessly. I added support for syncing critical files between routers:
config sync_group 'config_sync'
list sync_file '/etc/config/dhcp'
list sync_file '/etc/config/firewall'
list sync_file '/etc/config/network'
option sync_interval '60'
Files are synchronized via unicast or multicast every N seconds. The backup always has a fresh copy.
Status RPC and Service Improvements Link to heading
To integrate with OpenWrt's procd init system, I added an RPC endpoint that reports the current VRRP state:
# ubus call keepalived status
{
"instances": {
"lan": {
"state": "MASTER",
"virtual_ipaddress": "192.168.1.1",
"interface": "lan",
"priority": 100
}
}
}
This RPC call powers the LuCI web interface's real-time status display. It also enables monitoring scripts -- a cron job can poll this and alert you if a router is unexpectedly in BACKUP state.
The procd integration also handles:
- Automatic restart if keepalived crashes
- Clean shutdown on service stop
- Proper logging through the system log
LuCI Web Interface Link to heading
The LuCI app provides a full management interface for Keepalived:
Overview page -- shows the current state of every VRRP instance. A green badge for MASTER, yellow for BACKUP. At a glance, you know which router is active.
Globals configuration -- set the alternative config path, enable/disable SMTP alerts, configure notification scripts.
Virtual IP Addresses -- add, edit, and remove virtual IPs. Supports both /24 and individual /32 addresses.
Static IP addresses -- assign fixed addresses that are always present on the interface, regardless of VRRP state. Useful for management access.
Routes -- add static routes that are only active when this router is the VRRP master. Ensures traffic flows through the correct gateway.
Every change in LuCI writes to UCI, and the init script generates keepalived.conf from UCI on service start. No manual config editing required.
Why This Matters Link to heading
Before this contribution, Keepalived on OpenWrt required manually writing keepalived.conf -- error-prone and not integrated with the rest of the system. UCI integration means:
- Consistency -- Keepalived config lives alongside all other OpenWrt config in
/etc/config/ - Atomic changes -- UCI supports commit/rollback, so a bad config change doesn't break the running service
- Backup and restore --
sysupgradecaptures UCI config, so a router replacement has Keepalived ready to go - LuCI integration -- web-based management without SSH
Getting Started Link to heading
Install on OpenWrt:
opkg update
opkg install keepalived luci-app-keepalived
Navigate to Services -> Keepalived in LuCI. Configure your VRRP instance, set priorities, and both routers will negotiate the virtual IP automatically.
The package is in the official OpenWrt repository as of OpenWrt 23.05 and later.
Commits: d1a82d2 -- luci-app-keepalived: Add LuCI for keepalived - 33398a3 -- keepalived: high-availability files and data sync - 0f7415b -- keepalived: add status rpc and service improvement