//------------------------------------------------------------------- //-------------------------------------------------------------------
Keepalived VRRP HAProxy failover setup

How to Set Up Keepalived and VRRP for High-Availability Load Balancer Failover

Running a single HAProxy or Nginx load balancer is a single point of failure. If that one node crashes, every service behind it goes down. This guide walks through a complete Keepalived VRRP HAProxy failover setup.

By the end, you’ll have two servers sharing one virtual IP (VIP), automatic failover to the backup when the master goes down, and health checks that watch whether HAProxy itself is actually working, not just whether the server is on. If you haven’t set up HAProxy itself yet, check out our guide on configuring HAProxy as a high-performance reverse proxy first, then come back here to add redundancy.

What Keepalived VRRP HAProxy Failover Actually Solves

VRRP (Virtual Router Redundancy Protocol) lets two or more routers share one virtual IP address. Only one node, the MASTER, holds the VIP and answers traffic at any given time. The other node, the BACKUP, listens for VRRP advertisements over multicast or unicast and silently waits.

Keepalived is the Linux service that runs VRRP and handles this election process. If the MASTER stops sending signals because it crashed, lost network, or HAProxy crashed, the BACKUP takes over the VIP in one to three seconds. Clients keep hitting the same IP and never notice the switch.

This setup doesn’t split traffic between the two nodes; only one is ever active at a time. It just removes the load balancer itself as a single point of failure, while HAProxy still handles balancing traffic across your app servers as usual.

Architecture and Prerequisites

For this tutorial, we’ll use a two-node setup:

  • lb01 (10.0.0.11): Primary/MASTER node, HAProxy with Keepalived.
  • lb02 (10.0.0.12): Secondary/BACKUP node, HAProxy with Keepalived.
  • VIP: 10.0.0.10, the floating address clients and DNS actually point to.
  • Both nodes on the same Layer 2 network segment. VRRP requires this, since failover relies on ARP.
  • Ubuntu 22.04 or 24.04.
  • Root or sudo access on both nodes.
  • If you’re deploying on a cloud VPS or dedicated hardware, make sure the provider allows a secondary/floating IP or supports unicast VRRP.

A reliable Keepalived VRRP HAProxy failover deployment depends heavily on network latency between nodes, which is why running both in the same data center or region matters. Setting up two dedicated servers or VPS instances in the same region keeps VRRP latency low and failover detection fast.

Step 1. Install HAProxy on Both Nodes

Run this on both lb01 and lb02 nodes because both nodes need the same HAProxy configuration:

sudo apt update
sudo apt install haproxy -y
haproxy -v

Both nodes need the /etc/haproxy/haproxy.cfg so either one can handle traffic on its own. To create the file, open it with your desired text editor on each node:

sudo nano /etc/haproxy/haproxy.cfg

Add this minimal example:

global
    log /dev/log local0
    maxconn 4096

defaults
    mode http
    timeout connect 5s
    timeout client 30s
    timeout server 30s

frontend fe_main
    bind 10.0.0.10:80
    default_backend be_web

backend be_web
    balance roundrobin
    server web1 10.0.0.21:80 check
    server web2 10.0.0.22:80 check

Notice HAProxy binds to the VIP (10.0.0.10), not the server’s own IP. The BACKUP node doesn’t have that VIP yet, so HAProxy needs permission to bind to an address it doesn’t own yet:

echo "net.ipv4.ip_nonlocal_bind = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Without this sysctl setting, HAProxy will fail to start on the BACKUP node, and your Keepalived VRRP HAProxy failover will silently break the moment a failover occurs.

Enable HAProxy at boot but don’t start it manually yet if you want Keepalived’s notify scripts to control it. For now, enable and start it normally:

sudo systemctl enable haproxy
sudo systemctl start haproxy
sudo systemctl status haproxy

Step 2. Install Keepalived on Both Nodes

On both nodes, run the commands below to install Keepalived:

sudo apt update
sudo apt install keepalived -y
keepalived --version

Enable IP forwarding and non-local binding, which every Keepalived VRRP HAProxy failover node requires system-wide:

sudo tee -a /etc/sysctl.conf <<EOF
net.ipv4.ip_forward = 1
net.ipv4.ip_nonlocal_bind = 1
EOF
sudo sysctl -p

Step 3. Write the Health-Check Script for Keepalived VRRP HAProxy Failover

Keepalived needs a way to know HAProxy is actually healthy, not just that the OS is up. Create this script on both nodes so the Keepalived VRRP HAProxy failover election reacts to real HAProxy health, not just server uptime:

sudo tee /etc/keepalived/check_haproxy.sh <<'EOF'
#!/bin/bash
if systemctl is-active --quiet haproxy; then
    exit 0
else
    exit 1
fi
EOF

sudo chmod +x /etc/keepalived/check_haproxy.sh

This just checks if the HAProxy process is running. For a stricter check that confirms HAProxy is actually accepting connections, replace it with a curl request to HAProxy’s stats page instead of just checking the systemd status.

Step 4. Configure Keepalived on the Master Node (lb01)

To configure Keepalived on the master node (lb01), create the following file:

sudo nano /etc/keepalived/keepalived.conf

Add this config:

global_defs {
    router_id LB01
    enable_script_security
    script_user root
}

vrrp_script chk_haproxy {
    script "/etc/keepalived/check_haproxy.sh"
    interval 2
    timeout 2
    fall 2
    rise 2
    weight 20
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 150
    advert_int 1
    nopreempt

    authentication {
        auth_type PASS
        auth_pass K3ep@liv
    }

    virtual_ipaddress {
        10.0.0.10/24
    }

    track_script {
        chk_haproxy
    }

    notify_master "/etc/keepalived/notify.sh MASTER"
    notify_backup "/etc/keepalived/notify.sh BACKUP"
    notify_fault  "/etc/keepalived/notify.sh FAULT"
}

A few details matter here for a correct Keepalived VRRP HAProxy failover configuration:

  • Set both nodes to state BACKUP; priority decides who wins. This is required for nopreempt to work.
  • virtual_router_id must match on both nodes so they recognize each other.
  • lb01 has higher priority, so it becomes MASTER first.
  • auth_pass can’t exceed 8 characters; keepalived cuts off anything longer.
  • nopreempt stops lb01 from grabbing the VIP back right after it recovers, avoiding a second failover. Remove it if you want lb01 to always take over again once it’s healthy.

Step 5. Configure Keepalived on the Backup Node (lb02)

Create the matching /etc/keepalived/keepalived.conf file on lb02:

global_defs {
    router_id LB02
    enable_script_security
    script_user root
}

vrrp_script chk_haproxy {
    script "/etc/keepalived/check_haproxy.sh"
    interval 2
    timeout 2
    fall 2
    rise 2
    weight 20
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    nopreempt

    authentication {
        auth_type PASS
        auth_pass K3ep@liv
    }

    virtual_ipaddress {
        10.0.0.10/24
    }

    track_script {
        chk_haproxy
    }

    notify_master "/etc/keepalived/notify.sh MASTER"
    notify_backup "/etc/keepalived/notify.sh BACKUP"
    notify_fault  "/etc/keepalived/notify.sh FAULT"
}

The auth_pass and virtual_router_id must match between nodes or the two Keepalived processes will never recognize each other as peers in the same Keepalived VRRP HAProxy failover group.

Step 6. Add Notify Scripts for Logging and Alerts

At this point, you must create the Notify Scripts file on both nodes so you get a log entry every time a role transition happens.

Create the file and make the file executable:

sudo tee /etc/keepalived/notify.sh <<'EOF'
#!/bin/bash
STATE=$1
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "$DATE - Keepalived transitioned to $STATE" >> /var/log/keepalived-state.log
EOF

sudo chmod +x /etc/keepalived/notify.sh

Note: Swap the echo line for a curl call to Slack, PagerDuty, or your monitoring tool if you want real-time alerts whenever a failover happens.

Step 7. Handle Cloud and Firewall Restrictions

A Keepalived VRRP HAProxy failover deployment on public cloud usually breaks here:

Standard VRRP uses multicast (224.0.0.18) and the IP protocol number 112. Many cloud providers block multicast and non-standard protocols on their virtual networks, which silently breaks failover.

Two fixes for this, include:

1. Switch to unicast VRRP: Add these lines inside vrrp_instance on each node, pointing to the peer’s IP:

unicast_src_ip 10.0.0.11
unicast_peer {
    10.0.0.12
}

On lb02, swap the IPs, unicast_src_ip becomes 10.0.0.12, and the peer becomes 10.0.0.11.

2. Open the firewall for VRRP if you’re not using unicast:

sudo ufw allow from 10.0.0.0/24 to any proto vrrp
sudo ufw allow from 224.0.0.18

On cloud VPS platforms, check whether you need to manually attach the floating IP to the active instance. Some providers, don’t support the standard ARP-based VIP failover at all; you’d need the notify script to call their API instead to move the IP. This is the most common reason a correctly Keepalived VRRP HAProxy failover setup still fails on public cloud.

Step 8. Start Keepalived and Verify the VIP

Start the service on both nodes:

sudo systemctl enable keepalived
sudo systemctl start keepalived
sudo systemctl status keepalived

On lb01, confirm the VIP is attached:

ip addr show eth0

You should see 10.0.0.10/24 listed as a secondary address on lb01, and absent from lb02’s interface.

Check the Keepalived logs to confirm the election:

sudo journalctl -u keepalived -f

You should see lb01 log Entering MASTER STATE and lb02 log Entering BACKUP STATE. This confirms the base Keepalived VRRP HAProxy failover election is working before you move on to failure testing.

Step 9. Test Failover

At this point, you can prove that your Keepalived VRRP HAProxy failover setup works.

Test 1. stop HAProxy on the master:

# On lb01
sudo systemctl stop haproxy

Within a few seconds, chk_haproxy should fail, drop lb01’s priority by the configured weight, and lb02 should take over the VIP.

Confirm with the command below on lb02:

ip addr show eth0

Check on both nodes:

journalctl -u keepalived -f

Test 2. simulate a full node outage:

# On lb01
sudo systemctl stop keepalived

lb02 should promote itself the moment it stops receiving VRRP advertisements from lb01.

Test 3. continuous connectivity check from a third machine:

while true; do curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" http://10.0.0.10/; sleep 1; done

Run this while doing Test 1 or Test 2. You should see at most one or two failed requests during the switch. This is the proof your Keepalived VRRP HAProxy failover actually works.

Then, restart HAProxy and Keepalived on lb01:

sudo systemctl start haproxy keepalived

Conform it rejoins as BACKUP without taking the VIP back, thanks to nopreempt.

Step 10. Harden and Monitor the Cluster

A few extra steps worth adding once your Keepalived VRRP HAProxy failover setup is working:

  • Add garp_master_delay and garp_master_refresh to vrrp_instance to keep re-announcing the VIP. This helps on switches that clear ARP cache quickly.
  • Send VRRP state changes to your logging tool through the notify script instead of just a text file.
  • With more than two nodes, keep one virtual_router_id per VIP group and use priority to rank the backups.
  • If HAProxy handles TLS, run separate failover pairs for HTTP and HTTPS, and keep certificates synced between lb01 and lb02.
  • Re-run the failover tests from Step 9 after any OS or Keepalived update; outdated configs are the most common cause of failover breaking later.

Conclusion

A single load balancer is always one failure away from an outage. Pairing HAProxy with Keepalived and VRRP turns two separate servers into one self-healing pair that keeps the same virtual IP alive even if one node goes down. With health checks driving the failover, nopreempt preventing needless switches, and unicast VRRP handling cloud restrictions, you now have a setup that’s actually ready for production.

Just make sure both nodes sit on reliable and low-latency hosting in the same region, since VRRP’s failover speed depends on how fast the two servers can talk to each other.

We hope you enjoy this Keepalived VRRP HAProxy failover setup.

For more information about every Keepalived directive used above, check out the official Keepalived configuration manual.

FAQs

What is VRRP used for in a Keepalived HAProxy setup?

VRRP lets two servers share one virtual IP address, with only one node active at a time, so traffic keeps flowing if the active node fails.

Can Keepalived work with Nginx instead of HAProxy?

Yes. Swap the health-check script to monitor the Nginx process or systemd unit instead of HAProxy; the VRRP and Keepalived configuration stays the same.

Why do both nodes need “state BACKUP” if one should be master?

Setting both to BACKUP and using priority lets nopreempt work correctly, avoiding a double failover when the original master recovers.

Does Keepalived load-balance traffic between the two nodes?

No. Only one node holds the VIP and serves traffic at a time; load balancing across backend servers is HAProxy’s job, not Keepalived’s.

Post Your Comment

PerLod delivers high-performance hosting with real-time support and unmatched reliability.

Contact us

Payment methods

payment gateway
Perlod Logo
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.