You are currently viewing haproxy keepalived vrrp high availability load balancer active passive linux setup: 7 Proven, Easy Steps

haproxy keepalived vrrp high availability load balancer active passive linux setup: 7 Proven, Easy Steps

  • Post author:
  • Post category:Tutorials
  • Post comments:0 Comments
  • Reading time:5 mins read

Table of Contents

Overview

This guide builds a highly available load balancer using HAProxy for traffic proxying and Keepalived for VRRP failover. With two nodes sharing a virtual IP (VIP), traffic continues even if the active node fails. Includes per-distro installation steps and unified configs you can copy-paste.

Prerequisites

  • Two Linux servers with sudo: LB1 and LB2.
  • A real subnet and a free Virtual IP (VIP), e.g., 192.0.2.100/24.
  • Open ports: TCP 80/443 (or your app ports); VRRP protocol 112 allowed between LBs.
  • Placeholders: VIP, VIP_IF (e.g., eth0), ROUTER_ID, BACKEND1_IP, BACKEND2_IP, DOMAIN.
  • Distros covered: Ubuntu/Debian, RHEL-family (RHEL/Rocky/CentOS Stream/Fedora), Arch/Manjaro, openSUSE/SLE.

Quick Architecture</h2

haproxy keepalived vrrp high availability load balancer active passive linux setup

Install / Setup

1) Install HAProxy and Keepalived on both LB1 and LB2.

Ubuntu/Debian

sudo apt update && sudo apt install -y haproxy keepalived

RHEL-Family (RHEL/Rocky/CentOS Stream/Fedora)

sudo dnf -y install haproxy keepalived

Arch / Manjaro

sudo pacman -Sy --noconfirm haproxy keepalived

openSUSE / SLE

sudo zypper refresh && sudo zypper install -y haproxy keepalived

2) Enable IP forwarding and non-local bind (required for VIP takeover).

sudo tee /etc/sysctl.d/99-ha-lb.conf > /dev/null <<'SYSCTL'
net.ipv4.ip_forward=1
net.ipv4.ip_nonlocal_bind=1
SYSCTL
sudo sysctl --system

3) (Optional) Spin up two simple backends (Nginx) for demo.

# On BACKEND1 and BACKEND2 (example backends)
sudo apt update && sudo apt install -y nginx 2>/dev/null || sudo dnf -y install nginx 2>/dev/null || sudo zypper -n install nginx 2>/dev/null || sudo pacman -Sy --noconfirm nginx 2>/dev/null
echo "Hello from $(hostname)" | sudo tee /usr/share/nginx/html/index.html
sudo systemctl enable --now nginx

Base Configuration

4) Configure HAProxy (same file on LB1 and LB2). Paste this full file in one go.

# /etc/haproxy/haproxy.cfg
sudo tee /etc/haproxy/haproxy.cfg > /dev/null <<'HAP'
global
  log /dev/log local0
  log /dev/log local1 notice
  maxconn 4096
  daemon

defaults
  log     global
  mode    http
  option  httplog
  option  dontlognull
  timeout connect 5s
  timeout client  50s
  timeout server  50s

frontend fe_http
  bind *:80
  bind *:443 ssl crt /etc/ssl/private/DOMAIN.pem alpn h2,http/1.1
  default_backend be_app

backend be_app
  balance roundrobin
  option httpchk GET /
  server app1 BACKEND1_IP:80 check
  server app2 BACKEND2_IP:80 check

listen stats
  bind *:8404
  stats enable
  stats uri /
  stats refresh 5s
HAP

5) Provide a TLS certificate if you terminate HTTPS on HAProxy (optional).

# Place PEM at /etc/ssl/private/DOMAIN.pem (key + cert chain concatenated)

6) Configure Keepalived with VRRP on both nodes. LB1 is MASTER (higher priority) and LB2 is BACKUP.

# /etc/keepalived/keepalived.conf (LB1 - MASTER)
sudo tee /etc/keepalived/keepalived.conf > /dev/null <<'KVA'
vrrp_instance VI_1 {
  state MASTER
  interface VIP_IF
  virtual_router_id ROUTER_ID
  priority 101
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass StrongVRRPpass
  }
  virtual_ipaddress {
    VIP/24
  }
  track_script {
    chk_haproxy
  }
}

vrrp_script chk_haproxy {
  script "/usr/bin/pgrep -f 'haproxy.*-Ws' || /usr/bin/pgrep haproxy"
  interval 2
  weight -20
}
KVA
# /etc/keepalived/keepalived.conf (LB2 - BACKUP)
sudo tee /etc/keepalived/keepalived.conf > /dev/null <<'KVB'
vrrp_instance VI_1 {
  state BACKUP
  interface VIP_IF
  virtual_router_id ROUTER_ID
  priority 100
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass StrongVRRPpass
  }
  virtual_ipaddress {
    VIP/24
  }
  track_script {
    chk_haproxy
  }
}

vrrp_script chk_haproxy {
  script "/usr/bin/pgrep -f 'haproxy.*-Ws' || /usr/bin/pgrep haproxy"
  interval 2
  weight -20
}
KVB

Reload/Enable & Health Checks

7) Enable and start services on both nodes.

sudo systemctl enable --now haproxy
sudo systemctl enable --now keepalived

8) Validate VIP assignment and failover.

ip addr show dev VIP_IF | sed -n '1,120p' | grep -E "inet .*VIP" || echo "VIP not on this node"
sudo ss -lntp | grep -E ':(80|443|8404)'
curl -s http://VIP | head -n 2
# Simulate failover:
# sudo systemctl stop haproxy
# Then verify VIP moves to LB2.

Security / Hardening

# Allow only required ports (adjust firewall for your distro)
sudo ufw allow 80/tcp 2>/dev/null || true
sudo ufw allow 443/tcp 2>/dev/null || true
sudo ufw allow 8404/tcp 2>/dev/null || true
# VRRP uses protocol 112 (multicast 224.0.0.18) between LBs — allow it on your firewall
sudo ufw enable 2>/dev/null || true

# Systemd hardening for HAProxy (drop-in)
sudo mkdir -p /etc/systemd/system/haproxy.service.d
sudo tee /etc/systemd/system/haproxy.service.d/override.conf > /dev/null <<'OVR'
[Service]
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
OVR

sudo systemctl daemon-reload && sudo systemctl restart haproxy

Performance & Optimization

  • Set proper health checks (httpchk) and timeouts matching your app latency.
  • Prefer HTTP/2 on TLS frontends (ALPN h2) if your clients support it.
  • Tune maxconn and observe with the HAProxy stats page (:8404).
  • Use DNS resolvers for dynamic backends or cloud load balancers.
# DNS resolvers for dynamic backends (append to haproxy.cfg)
sudo tee -a /etc/haproxy/haproxy.cfg > /dev/null <<'HAP2'
resolvers dns
  nameserver google 8.8.8.8:53
  hold valid 10s

backend be_app
  balance roundrobin
  option httpchk GET /healthz
  default-server init-addr last,libc,none resolvers dns check inter 2s fall 3 rise 2
HAP2
sudo systemctl reload haproxy

Backup & Restore

sudo tar czf ha-lb-backup-$(date +%F).tgz /etc/haproxy /etc/keepalived /etc/sysctl.d/99-ha-lb.conf
# Restore:
# sudo tar xzf ha-lb-backup-YYYY-MM-DD.tgz -C /
# sudo sysctl --system
# sudo systemctl restart haproxy keepalived

Troubleshooting (Top issues)

1) VIP never appears — kernel settings or interface name wrong.

sysctl net.ipv4.ip_nonlocal_bind; sysctl net.ipv4.ip_forward; ip link show

2) Failover slow — check VRRP adverts and priorities.

grep -n 'advert_int\|priority' /etc/keepalived/keepalived.conf

3) Backends always down — health check path wrong or firewall blocking 80.

sudo ss -lntp | grep :80 || true; curl -I http://BACKEND1_IP/ || true

4) TLS errors — missing PEM chain or wrong file path.

sudo ls -l /etc/ssl/private/; openssl x509 -noout -text -in /etc/ssl/private/DOMAIN.pem | head -n 20

Key Takeaways & Next Steps

  • Keepalived provides fast VRRP failover; HAProxy handles L7/L4 proxying.
  • Harden services and restrict admin endpoints; monitor with stats.
  • Next: add Prometheus exporters and alerts for LB health.

Leave a Reply