The Need for High Availability
In modern web infrastructure, a single server is a single point of failure. If your primary web server goes offline due to hardware failure, kernel panic, or network disruption, your application goes down with it. High Availability (HA) architectures solve this by running multiple identical servers and placing a load balancer in front of them.
However, the load balancer itself can become a single point of failure. To achieve true HA, you need multiple load balancers that monitor each other and can instantly take over a shared Virtual IP (VIP) if the primary load balancer fails. On Ubuntu Linux, this is achieved by pairing HAProxy (for load balancing) with Keepalived (for VIP failover using the VRRP protocol).
Prerequisites
For this architecture, you need at least two Ubuntu 24.04 servers acting as load balancers (LB1 and LB2). They must be on the same Layer 2 network subnet so they can share a Virtual IP address (e.g., 192.168.1.100).
Step 1: Installing Keepalived and HAProxy
Log into both LB1 and LB2 and install the necessary packages using the APT package manager:
sudo apt update
sudo apt install haproxy keepalived -y
Additionally, you must configure the Linux kernel to allow applications to bind to a non-local IP address. This is required because HAProxy needs to listen on the VIP, even if the VIP is currently hosted by the other node.
echo "net.ipv4.ip_nonlocal_bind=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Step 2: Configuring HAProxy
On both LB1 and LB2, configure HAProxy to listen on the Virtual IP address and forward traffic to your backend web servers. Edit /etc/haproxy/haproxy.cfg:
frontend http_front
bind 192.168.1.100:80
default_backend web_servers
backend web_servers
balance roundrobin
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 check
Restart HAProxy on both nodes to apply the changes:
sudo systemctl restart haproxy
Step 3: Configuring Keepalived on the Primary Node (LB1)
Keepalived manages the Virtual IP using the Virtual Router Redundancy Protocol (VRRP). Edit /etc/keepalived/keepalived.conf on the Primary Node (LB1):
vrrp_script chk_haproxy {
script "killall -0 haproxy"
interval 2
weight 20
}
vrrp_instance VI_1 {
interface eth0
state MASTER
virtual_router_id 51
priority 101
virtual_ipaddress {
192.168.1.100
}
track_script {
chk_haproxy
}
}
This configuration tells Keepalived to claim the MASTER state and bind the 192.168.1.100 VIP to the eth0 interface. The chk_haproxy script runs every 2 seconds to ensure the HAProxy process is actually running; if HAProxy crashes, Keepalived will drop its priority, allowing the backup node to take over.
Step 4: Configuring Keepalived on the Backup Node (LB2)
On the Backup Node (LB2), edit the /etc/keepalived/keepalived.conf file similarly, but change the state to BACKUP and lower the priority:
vrrp_script chk_haproxy {
script "killall -0 haproxy"
interval 2
weight 20
}
vrrp_instance VI_1 {
interface eth0
state BACKUP
virtual_router_id 51
priority 100
virtual_ipaddress {
192.168.1.100
}
track_script {
chk_haproxy
}
}
Step 5: Starting the Services and Testing Failover
Start and enable the Keepalived service on both nodes:
sudo systemctl enable --now keepalived
If you run ip addr show eth0 on LB1, you will see the Virtual IP assigned to the interface. On LB2, it will not be present. If you stop the HAProxy service on LB1 (sudo systemctl stop haproxy), Keepalived will detect the failure via the tracking script and immediately transition the VIP to LB2. Your applications will experience less than a second of downtime during the failover.
Combining HAProxy with Keepalived on Ubuntu provides a robust, enterprise-grade High Availability load balancing tier. This architecture ensures that neither the backend servers nor the load balancers themselves can cause a total system outage.