Skip to content

pgaufillet/openwrt-ha-feed

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenWrt HA Cluster Feed

A high-availability solution for OpenWrt routers, providing automatic failover, configuration synchronization, and DHCP lease replication.

Features

  • Virtual IP Failover - VRRP-based failover with sub-second switchover (keepalived)
  • Configuration Sync - Bi-directional, encrypted sync of UCI configs between nodes (owsync)
  • DHCP Lease Sync - Real-time lease replication for seamless client experience (lease-sync)
  • Web Interface - LuCI integration for easy setup and monitoring
  • IPv4 and IPv6 - Full dual-stack support for VIPs and sync traffic

Packages

Package Description
ha-cluster Core orchestration - manages keepalived, owsync, and lease-sync
luci-app-ha-cluster Web interface for configuration and monitoring
owsync Lightweight encrypted file synchronization daemon
lease-sync Real-time DHCP lease replication daemon
dnsmasq-ha dnsmasq with ubus lease management patches

Requirements

  • OpenWrt 24.10
  • Two or more routers on a shared network segment
  • dnsmasq-ha (for DHCP lease sync)

Installation

Add the Feed

# Add feed to /etc/openwrt_distfeeds.conf or feeds.conf
echo "src-git hacluster https://github.com/pgaufillet/openwrt-ha-feed.git" >> feeds.conf

# Update and install
./scripts/feeds update hacluster
./scripts/feeds install -a -p hacluster

Install Packages

# Install the complete HA solution
opkg update
opkg install ha-cluster luci-app-ha-cluster

# Or install individual components
opkg install owsync        # Config sync only
opkg install lease-sync    # DHCP sync only

Quick Start

Quick Setup (5 minutes)

On both routers:

  1. Install packages:

    opkg update
    opkg install ha-cluster luci-app-ha-cluster
  2. Open LuCI: Services → High Availability → Quick Setup

  3. Configure:

    • Enable HA Cluster
    • Set node name (e.g., router1, router2)
    • Set priority (higher = preferred master, e.g., 100 and 90)
    • Add peer IP address
    • Add Virtual IP for your LAN interface
    • Generate and copy encryption key to both nodes
  4. Save & Apply

  5. Verify: Check Status tab for cluster health

Manual Configuration

Edit /etc/config/ha-cluster:

config global 'config'
    option enabled '1'
    option node_priority '100'
    option encryption_key '0123456789abcdef...'  # 64 hex chars

config peer
    option name 'router2'
    option address '192.168.1.2'

config vrrp_instance 'main'
    option vrid '51'
    option interface 'lan'
    option priority '100'
    option nopreempt '1'

config vip 'lan'
    option enabled '1'
    option vrrp_instance 'main'
    option interface 'br-lan'
    option address '192.168.1.254'
    option netmask '255.255.255.0'

Start the cluster:

/etc/init.d/ha-cluster enable
/etc/init.d/ha-cluster start

Architecture

┌───────────────────────────────────────────────────────┐
│                      ha-cluster                       │
│                  (Orchestration Layer)                │
└───────┬──────────────────┬──────────────────┬─────────┘
        │                  │                  │
        ▼                  ▼                  ▼
┌─────────────────┐ ┌──────────────┐ ┌──────────────────┐
│   keepalived    │ │   owsync     │ │   lease-sync     │
│     (VRRP)      │ │ (Config Sync)│ │  (DHCP Sync)     │
└─────────────────┘ └──────────────┘ └──────────────────┘
  • keepalived: Manages VRRP for virtual IP failover
  • owsync: Syncs UCI configuration files with AES-256-GCM encryption
  • lease-sync: Replicates DHCP leases in real-time via ubus and UDP with AES-256-GCM encryption

Documentation

Security

  • Encryption: All sync traffic encrypted with AES-256-GCM (PSK)
  • Key Management: Keys stored in config files, never exposed on command line
  • Network: Designed for trusted LAN segments; use VPN for untrusted networks

Known Limitations (v1.0)

IPv6 Support

What works:

  • IPv6 Virtual IPs (dual-stack VIP failover)
  • IPv6 sync traffic between nodes
  • SLAAC (default OpenWrt) - clients self-configure, no lease sync needed
  • Prefix Delegation from ISP - unaffected (odhcp6c is separate)
  • PD delegation to downstream routers - works (downstream may get different prefix on failover, which is normal IPv6 renumbering behavior)

What doesn't work:

  • Stateful DHCPv6 lease sync when using odhcpd (OpenWrt's default DHCPv6 server)

Why: lease-sync integrates with dnsmasq, not odhcpd. Since default OpenWrt uses SLAAC (stateless), most users are unaffected.

Recommended Workaround - Disable odhcpd: The simplest and most reliable approach for v1.0:

# Disable odhcpd, let dnsmasq handle all DHCP/RA
uci set dhcp.odhcpd.enabled='0'
uci set dhcp.lan.dhcpv6='server'
uci set dhcp.lan.ra='server'
uci commit dhcp
/etc/init.d/odhcpd stop
/etc/init.d/dnsmasq restart

This enables full DHCPv6 lease sync but loses odhcpd-specific features (PD relay, NDP proxy).

Advanced Workaround - Hybrid Architecture (UNTESTED): For experienced users who need odhcpd's unique features:

# /etc/config/dhcp - dnsmasq handles RA + DHCPv6 + DNS (lease-sync works)
config dhcp 'lan'
    option interface 'lan'
    option dhcpv4 'server'
    option dhcpv6 'server'      # dnsmasq handles DHCPv6 addresses
    option ra 'server'          # dnsmasq sends RA

# CRITICAL: Explicitly disable odhcpd on LAN interface
config dhcp 'lan_odhcpd'
    option interface 'lan'
    option ra 'disabled'        # Don't send RA (dnsmasq does it)
    option dhcpv6 'disabled'    # Don't do DHCPv6 (dnsmasq does it)
    option ndp 'hybrid'         # NDP proxy only

# odhcpd global settings
config odhcpd 'odhcpd'
    option maindhcp '0'

This should preserve:

  • ✅ DHCPv6 lease sync (via dnsmasq + lease-sync)
  • ✅ NDP proxy (odhcpd)
  • ⚠️ PD relay to downstream (works, but downstream may experience lease expiration delay on failover)

⚠️ Warning: This hybrid configuration has not been tested in production. Requires experienced user configuration. Please report any issues.

Troubleshooting

Check Cluster Status

# Via CLI
ubus call ha-cluster status

# Via LuCI
Services → High Availability → Status

View Logs

logread | grep -E "(ha-cluster|keepalived|owsync|lease-sync)"

Common Issues

Issue Solution
VIP not appearing Check interface name matches UCI config
Sync not working Verify encryption keys match on both nodes
Peer unreachable Check firewall allows ports 4321 (owsync), 4322 (lease-sync), 112 (VRRP)
Split brain Ensure reliable network between nodes

Development

Setting Up the Build Environment

A setup script is provided to clone and configure an OpenWrt buildroot for compiling the feed packages:

# Default setup (OpenWrt 24.10.5, x86_64 config)
scripts/setup-openwrt-buildroot.sh ../openwrt

# Build all packages
cd ../openwrt
make package/ha-cluster/compile V=s
make package/owsync/compile V=s
make package/lease-sync/compile V=s
make package/dnsmasq-ha/compile V=s
make package/luci-app-ha-cluster/compile V=s

Built .ipk files are output to bin/packages/*/ha_feed/.

See scripts/setup-openwrt-buildroot.sh --help for options (custom OpenWrt version, config file, etc.).

Building and Hosting Your Own Package Repository

If you want to serve pre-built packages to your routers without compiling on the router itself, you can create a signed opkg feed hosted on any HTTP server on your LAN (NAS, Raspberry Pi, etc.).

1. Build the Packages

Follow the build environment setup above, then compile all packages:

cd ../openwrt
make package/ha-cluster/compile
make package/owsync/compile
make package/lease-sync/compile
make package/dnsmasq-ha/compile
make package/luci-app-ha-cluster/compile

Built .ipk files are in bin/packages/<arch>/ha_feed/ (e.g., bin/packages/aarch64_cortex-a53/ha_feed/).

2. Generate a Signing Key

# usign is built as part of the OpenWrt toolchain
USIGN=staging_dir/host/bin/usign

# Generate a keypair (do this once, keep the private key safe)
$USIGN -G -p keys/ha_feed.pub -s keys/ha_feed.sec

3. Generate and Sign the Package Index

The OpenWrt buildroot has a built-in target that generates the package index (Packages, Packages.gz, Packages.sig, index.json) and signs it. Pass BUILD_KEY to use your feed signing key instead of the default build key:

make package/index BUILD_KEY=/path/to/keys/ha_feed.sec

4. Deploy to a Web Server

Copy the .ipk files and index files to any directory served by an HTTP server:

FEED_DIR=bin/packages/<arch>/ha_feed
scp $FEED_DIR/*.ipk $FEED_DIR/Packages $FEED_DIR/Packages.gz $FEED_DIR/Packages.sig $FEED_DIR/index.json myserver:/var/www/openwrt/ha_feed/

5. Configure Routers to Use the Feed

On each router:

# Add the feed
echo "src/gz ha_feed http://myserver/openwrt/ha_feed" > /etc/opkg/customfeeds.conf

# Install the signing public key
# The key fingerprint is the filename under /etc/opkg/keys/
FINGERPRINT=$(usign -F -p /path/to/ha_feed.pub)
cp /path/to/ha_feed.pub /etc/opkg/keys/$FINGERPRINT

# Update and install
opkg update
opkg install ha-cluster luci-app-ha-cluster

6. Updating the Feed

After rebuilding packages, repeat steps 3 and 4 to regenerate the index and redeploy. For example, to rebuild only ha-cluster and luci-app-ha-cluster:

make package/ha-cluster/compile V=s
make package/luci-app-ha-cluster/compile V=s
make package/index BUILD_KEY=/path/to/keys/ha_feed.sec
scp bin/packages/<arch>/ha_feed/* myserver:/var/www/openwrt/ha_feed/

On routers, run opkg update to pick up the new versions.

Note: dnsmasq-ha replaces the stock dnsmasq package. On first install, you may need to remove dnsmasq manually before installing dnsmasq-ha:

# Save dnsmasq config, remove stock, install HA version
cp /etc/config/dhcp /tmp/dhcp.bak
opkg remove dnsmasq
opkg install dnsmasq-ha
cp /tmp/dhcp.bak /etc/config/dhcp
/etc/init.d/dnsmasq restart

Maintainer

Pierre Gaufillet pierre.gaufillet@bergamote.eu

About

A high-availability solution for OpenWrt routers, providing automatic failover, configuration synchronization, and DHCP lease replication.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors