Introduction
High availability for services requires both load balancing (HAProxy) and failover for the load balancer itself (Keepalived with VRRP). Together they create a fully redundant setup where a floating IP automatically moves to a standby server if the primary fails.
Architecture
TEXT
Clients → [Virtual IP: 10.0.0.100]
|
┌──────────┴──────────┐
[HAProxy-1 (Master)] [HAProxy-2 (Backup)]
10.0.0.10 10.0.0.11
| |
└──────────┬───────────┘
|
┌──────────┼──────────┐
[Web-1:80] [Web-2:80] [Web-3:80]Installing HAProxy
BASH
apt install haproxyEdit /etc/haproxy/haproxy.cfg:
TEXT
global
log /dev/log local0
log /dev/log local1 notice
maxconn 50000
user haproxy
group haproxy
daemon
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor
option http-server-close
retries 3
timeout connect 5s
timeout client 30s
timeout server 30s
# Statistics page
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 10s
stats auth admin:yourpassword
# Frontend: what HAProxy listens on
frontend web-frontend
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/combined.pem
# Redirect HTTP to HTTPS
redirect scheme https if !{ ssl_fc }
# Route by path
acl is_api path_beg /api/
use_backend api-servers if is_api
default_backend web-servers
# Backend: the actual servers
backend web-servers
balance roundrobin
option httpchk GET /health HTTP/1.1
Host: localhost
http-check expect status 200
server web-1 10.0.1.10:80 check inter 2s rise 2 fall 3
server web-2 10.0.1.11:80 check inter 2s rise 2 fall 3
server web-3 10.0.1.12:80 check inter 2s rise 2 fall 3 backup
backend api-servers
balance leastconn
option httpchk GET /api/health
server api-1 10.0.2.10:8080 check
server api-2 10.0.2.11:8080 checkInstalling Keepalived (VRRP Failover)
BASH
apt install keepalivedMaster Configuration (10.0.0.10)
Create /etc/keepalived/keepalived.conf:
TEXT
vrrp_script check_haproxy {
script "killall -0 haproxy" # Check if haproxy is running
interval 2
weight -20 # Reduce priority by 20 if check fails
fall 2
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51 # Same on both nodes
priority 100 # Higher = preferred master
advert_int 1 # Send VRRP advertisements every 1 second
authentication {
auth_type PASS
auth_pass YourSecretPass123
}
virtual_ipaddress {
10.0.0.100/24 dev eth0 # The floating IP
}
track_script {
check_haproxy
}
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
}Backup Configuration (10.0.0.11)
Same file but change:
TEXT
state BACKUP
priority 90 # Lower than masterNotification Script
BASH
cat > /etc/keepalived/notify.sh << 'EOF'
#!/bin/bash
TYPE=$1
DATE=$(date +'%Y-%m-%d %H:%M:%S')
echo "$DATE - Keepalived state: $TYPE" >> /var/log/keepalived-state.log
echo "HAProxy node $(hostname) became $TYPE at $DATE" | mail -s "HAProxy Failover: $TYPE" admin@company.com
EOF
chmod +x /etc/keepalived/notify.shStarting Services
BASH
# On both nodes
systemctl enable haproxy keepalived
systemctl start haproxy keepalived
# Check VIP assignment (only on master)
ip addr show eth0 | grep 10.0.0.100
# View keepalived logs
journalctl -u keepalived -fTesting Failover
BASH
# Continuous test from client
while true; do curl -s http://10.0.0.100/ | grep "server-name"; sleep 1; done
# On master: stop haproxy
systemctl stop haproxy
# VIP should move to backup within 2-4 seconds
# Or disconnect network on master
ip link set eth0 down
# VIP moves to backup immediatelyHAProxy Health Check Examples
TEXT
# HTTP health check
option httpchk GET /health
http-check expect status 200
# TCP health check (for databases)
option tcp-check
# Custom health check script
external-check command /usr/lib/nagios/plugins/check_mysql
# Health check with specific host header
option httpchk GET /health HTTP/1.1
Host: api.company.comSSL Termination at HAProxy
BASH
# Combine certificate and key
cat /etc/ssl/certs/example.com.crt /etc/ssl/private/example.com.key > /etc/haproxy/certs/combined.pem
chmod 600 /etc/haproxy/certs/combined.pem
# Enable in HAProxy frontend
bind *:443 ssl crt /etc/haproxy/certs/combined.pem alpn h2,http/1.1
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets