Skip to main content
RunBook Academy

← All labs in Linux

Lab · intermediate · ~60 min

Lab: Keepalived failover - configure, test, document

B · Nested virtualisationC · Simulation

Objectives

  • Configure keepalived on two hosts
  • Verify VRRP election
  • Test failover
  • Document the configuration

Prerequisites

This lab configures keepalived for floating-IP failover between two hosts and tests the failover. By the end you will have a working setup and a tested procedure.

Tasks

Task 1: Install keepalived and the service it checks

The health check in Task 2 curls http://localhost/health. If nothing serves that path the check fails on both hosts from the moment keepalived starts, both get the weight -20 penalty, and the failover test in Task 8 cannot work — see the arithmetic below. Install the web server first, on both hosts:

sudo apt install -y keepalived nginx curl

# A /health endpoint that returns 200 and nothing else
sudo tee /etc/nginx/conf.d/health.conf >/dev/null <<'EOF'
server {
    listen 80 default_server;
    location /health { return 200 "ok\n"; add_header Content-Type text/plain; }
}
EOF
sudo nginx -t && sudo systemctl reload nginx

# Must return 200 on BOTH hosts before keepalived starts
curl -sf -o /dev/null -w '%{http_code}\n' http://localhost/health

Task 2: Configure the master

On host1 (will be master):

sudo tee /etc/keepalived/keepalived.conf <<EOF
global_defs {
    enable_script_security
    script_user keepalived_script
}

vrrp_script check_service {
    script "/usr/bin/curl -sf http://localhost/health || exit 1"
    interval 2
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass mysecret
    }
    virtual_ipaddress {
        10.0.0.100/24
    }
    track_script {
        check_service
    }
}
EOF

Two things about auth_pass. VRRP’s PASS authentication sends the value in clear text on the wire, so it prevents misconfiguration — two clusters on one segment adopting each other’s VIP — and provides no security against anyone who can capture traffic. And it is limited to 8 characters: keepalived silently truncates anything longer, so a 20-character “strong” password on one host and a different 20-character one that shares the first 8 will authenticate to each other.

Treat virtual_router_id as the thing that must be unique per segment, and put the real access control in the firewall (VRRP is IP protocol 112, multicast 224.0.0.18).

Task 3: Configure the backup

On host2 (will be backup):

sudo tee /etc/keepalived/keepalived.conf <<EOF
global_defs {
    enable_script_security
    script_user keepalived_script
}

vrrp_script check_service {
    script "/usr/bin/curl -sf http://localhost/health || exit 1"
    interval 2
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass mysecret
    }
    virtual_ipaddress {
        10.0.0.100/24
    }
    track_script {
        check_service
    }
}
EOF

Task 4: Start keepalived

On both hosts:

sudo systemctl enable --now keepalived

Task 5: Verify

On host1 (master):

ip addr show eth0 | grep 10.0.0.100

Should show the VIP.

On host2 (backup):

ip addr show eth0 | grep 10.0.0.100

Should NOT show the VIP.

Task 6: Test failover

Stop keepalived on host1:

ssh host1 "sudo systemctl stop keepalived"

On host2, the VIP should now be held:

ip addr show eth0 | grep 10.0.0.100

Verify the service works:

curl -I http://10.0.0.100/health

Task 7: Test preemption

Start keepalived on host1 again:

ssh host1 "sudo systemctl start keepalived"

By default, host1 (higher priority) takes back the VIP.

Task 8: Test health check failover

First confirm the starting state is the one the arithmetic assumes — both checks healthy, host1 holding the VIP:

# On both hosts
curl -sf -o /dev/null -w '%{http_code}\n' http://localhost/health   # 200 on both

Then break the service on host1 only:

sudo systemctl stop nginx

host1’s check now fails 3 times (fall 3 at interval 2, so about 6 seconds), its priority drops to 80, host2’s 90 wins, and the VIP migrates. Watch it happen rather than sleeping:

# On host2
sudo journalctl -u keepalived -f     # expect "Entering MASTER STATE"

Verify:

ip addr show eth0 | grep 10.0.0.100    # on host2
curl -I http://10.0.0.100/health       # service works

Restart the service on host1; the VIP returns.

Task 9: Document

KEEPALIVED TEST REPORT
Date: 2026-08-09
VIP: 10.0.0.100
Hosts: host1 (master, priority 100), host2 (backup, priority 90)
Auth: PASS shared secret
Health check: HTTP /health

Tests:
- Initial state: VIP on host1
- Failover: stopped keepalived on host1, VIP on host2
- Preemption: restarted host1, VIP back to host1
- Health check: stopped service, VIP on host2

Findings:
- All tests pass
- Health check triggers failover as expected
- Preemption works as expected

Deliverables

  • · Working keepalived configuration
  • · Failover test report
  • · Documented procedure

Verification status

Last reviewed
2026-08-09
Executed end to end
not yet run on hardware

The commands and configuration here have been reviewed against the verified software versions, but nobody has run this lab start to finish on a system meeting its prerequisites. Treat the Expected Outcome as the intended result rather than an observed one, and keep the Cleanup section to hand.