tutorial

How to Monitor Keepalived (VRRP/LVS) with Vigilmon

Keepalived provides two critical functions — Virtual Router Redundancy Protocol (VRRP) for IP failover and Linux Virtual Server (LVS) for load balancing — an...

Keepalived provides two critical functions — Virtual Router Redundancy Protocol (VRRP) for IP failover and Linux Virtual Server (LVS) for load balancing — and it runs silently in the background. When the MASTER node loses its virtual IP without promoting a BACKUP, or when an LVS real server is removed from rotation without anyone noticing, the failure is often discovered by end users, not by operations.

This tutorial shows you how to build complete observability for Keepalived using Vigilmon: monitoring VRRP state transitions, virtual IP reachability, LVS real server health, and the Keepalived daemon itself.


Why Keepalived needs external monitoring

Keepalived is designed to be self-healing, which means failures can hide for a long time:

  • VRRP split-brain — both nodes may believe they are MASTER if the VRRP multicast group becomes unavailable. Both nodes hold the virtual IP, causing ARP conflicts and packet loss.
  • Silent BACKUP promotion failure — if the MASTER fails but the BACKUP doesn't promote (firewall blocking VRRP multicast, misconfigured priority), the virtual IP disappears entirely.
  • LVS real server removal — Keepalived's health checks quietly remove real servers from the LVS pool when they fail. If all real servers fail, Keepalived may still be "healthy" while all traffic is dropped.
  • Daemon crash on reloadkeepalived --reload can crash on config syntax errors, silently dropping VRRP instances.
  • Virtual IP not responding — the virtual IP can be held by the MASTER node but the service listening on it can be down.

Monitoring Keepalived means watching the virtual IP, the VRRP state, the LVS pool, and the daemon — not just whether the process is running.


What you'll need

  • A Keepalived setup with at least one VRRP instance (MASTER + BACKUP nodes)
  • Root or sudo access to run keepalived_dbus, ipvsadm, or ip addr
  • A free Vigilmon account

Step 1: Monitor the virtual IP from the outside

The most important thing to monitor is the virtual IP itself. Add an HTTP or TCP monitor in Vigilmon targeting the VIP directly:

For an HTTP service behind the VIP:

  1. Monitors → New Monitor → HTTP
  2. URL: http://YOUR_VIRTUAL_IP/health (or the service's health endpoint)
  3. Expected status: 200
  4. Check interval: 1 minute
  5. Name: Keepalived VIP — HTTP

For a TCP service (database, SMTP, etc.):

  1. Monitors → New Monitor → TCP Port
  2. Hostname: YOUR_VIRTUAL_IP
  3. Port: 5432 (or your service port)
  4. Name: Keepalived VIP — TCP

This is your first line of defense. If the VIP stops responding, Vigilmon alerts regardless of what Keepalived thinks its state is.


Step 2: Monitor VRRP state on each node

On each Keepalived node, run a probe that checks the local VRRP state and pings a per-node heartbeat. This lets you detect state transitions (MASTER → BACKUP, or unexpected BACKUP → FAULT):

#!/bin/bash
# keepalived-vrrp-probe.sh
# Run on each node separately with separate heartbeat URLs

# Set this per-node:
# NODE_ROLE="master" on your expected MASTER
# NODE_ROLE="backup" on your expected BACKUP
NODE_ROLE="${KEEPALIVED_EXPECTED_ROLE:-master}"

MASTER_HEARTBEAT="https://vigilmon.online/api/heartbeat/YOUR_MASTER_HEARTBEAT"
BACKUP_HEARTBEAT="https://vigilmon.online/api/heartbeat/YOUR_BACKUP_HEARTBEAT"
LOG="/var/log/keepalived-probe.log"

# Check Keepalived is running
if ! systemctl is-active --quiet keepalived; then
    echo "$(date): FAIL — keepalived not running" >> "$LOG"
    exit 1
fi

# Detect current VRRP state by checking if the VIP is held locally
VIP="192.168.1.100"  # replace with your virtual IP
if ip addr show | grep -q "$VIP"; then
    current_state="MASTER"
else
    current_state="BACKUP"
fi

echo "$(date): Node is $current_state (expected: $NODE_ROLE)" >> "$LOG"

# Ping the appropriate heartbeat based on current state
if [ "$current_state" = "MASTER" ]; then
    curl -s "$MASTER_HEARTBEAT" --max-time 10 --retry 2
else
    curl -s "$BACKUP_HEARTBEAT" --max-time 10 --retry 2
fi

Set up two heartbeats in Vigilmon:

  • Keepalived MASTER Node — interval 2 minutes, expects a ping from whichever node holds the VIP
  • Keepalived BACKUP Node — interval 2 minutes, expects a ping from the non-VIP node

If both heartbeats stop (split-brain scenario where both nodes are confused), both alerts fire simultaneously.


Step 3: Monitor LVS real server pool health

If you use Keepalived for LVS load balancing, monitor the real server pool:

#!/bin/bash
# keepalived-lvs-probe.sh

HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_LVS_HEARTBEAT"
LOG="/var/log/keepalived-lvs-probe.log"
MIN_REAL_SERVERS=1  # alert if fewer than this many real servers are active

# Get active real server count from ipvsadm
active_count=$(ipvsadm -L -n 2>/dev/null | grep -c "->")

if [ "$active_count" -lt "$MIN_REAL_SERVERS" ]; then
    echo "$(date): FAIL — only $active_count real servers active (min: $MIN_REAL_SERVERS)" >> "$LOG"
    ipvsadm -L -n >> "$LOG"
    exit 1
fi

echo "$(date): LVS pool healthy — $active_count real servers active" >> "$LOG"
curl -s "$HEARTBEAT_URL" --max-time 10 --retry 2

Add to crontab on the MASTER node:

*/2 * * * * /opt/scripts/keepalived-lvs-probe.sh

In Vigilmon:

  1. Monitors → New Monitor → Heartbeat
  2. Name: Keepalived LVS Pool
  3. Interval: 5 minutes

Step 4: Use Keepalived's notify scripts to push state changes

Keepalived supports notify scripts that run on VRRP state transitions. Use these to immediately notify Vigilmon when a failover occurs:

#!/bin/bash
# /etc/keepalived/notify.sh
# Called by Keepalived on state change: $1=GROUP|INSTANCE $2=name $3=MASTER|BACKUP|FAULT

INSTANCE="$2"
STATE="$3"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

# Log the transition
echo "$TIMESTAMP: $INSTANCE transitioned to $STATE" >> /var/log/keepalived-transitions.log

# Ping a state-specific heartbeat
case "$STATE" in
  MASTER)
    curl -s "https://vigilmon.online/api/heartbeat/YOUR_FAILOVER_HEARTBEAT" --max-time 10
    ;;
  FAULT)
    # Don't ping — Vigilmon will alert on missed heartbeat
    # Optionally call an external webhook here
    ;;
  BACKUP)
    curl -s "https://vigilmon.online/api/heartbeat/YOUR_BACKUP_PROMOTION_HEARTBEAT" --max-time 10
    ;;
esac

Add to your Keepalived VRRP instance config (/etc/keepalived/keepalived.conf):

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    notify /etc/keepalived/notify.sh
    virtual_ipaddress {
        192.168.1.100
    }
}

The notify script fires immediately on state change — you'll know about a failover within seconds.


Step 5: Monitor the Keepalived daemon and config reload

#!/bin/bash
# keepalived-daemon-check.sh

HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/YOUR_DAEMON_HEARTBEAT"

if systemctl is-active --quiet keepalived; then
    curl -s "$HEARTBEAT_URL" --max-time 10
fi
* * * * * /opt/scripts/keepalived-daemon-check.sh

In Vigilmon:

  1. Monitors → New Monitor → Heartbeat
  2. Name: Keepalived Daemon
  3. Interval: 2 minutes — daemon crashes should alert fast

Step 6: Configure alerting

Route Keepalived alerts appropriately by severity:

  1. Alert Channels → Add Channel → PagerDuty — for VIP down and FAULT state (production-impacting)
  2. Add Channel → Slack#infra-alerts for all transitions including MASTER→BACKUP
  3. Add Channel → Email — on-call engineer for daemon health

Set 0-minute escalation on the VIP HTTP/TCP monitor — if the VIP is unreachable, every second counts.


Step 7: Build a high-availability status page

  1. Status Pages → New Status Page
  2. Name: HA Infrastructure
  3. Add monitors: VIP HTTP, MASTER Node, BACKUP Node, LVS Pool, Daemon
  4. Set visibility to internal team
  5. Post the URL in #infra

This gives on-call engineers an instant answer to "is it the VIP, the MASTER, or the pool?"


Complete monitoring reference

| Monitor | Type | What it catches | |---------|------|-----------------| | Keepalived VIP — HTTP | HTTP | VIP unreachable, service down | | Keepalived VIP — TCP | TCP | VIP unreachable at transport layer | | MASTER Node state | Heartbeat | VIP holder down, no-MASTER state | | BACKUP Node state | Heartbeat | BACKUP not promoting, split-brain | | LVS Pool | Heartbeat | All real servers removed from pool | | Keepalived Daemon | Heartbeat | Daemon crash, failed reload | | VRRP notify script | Heartbeat | Failover event detection |


Troubleshooting common failures

  • VIP not responding but ip addr shows it on MASTER — the service on the VIP is down. Check systemctl status <service> and ss -tlnp | grep <port>.
  • No node holds the VIP — check VRRP multicast is not blocked: tcpdump -i eth0 vrrp should show VRRP advertisements every second. If silent, check firewall rules for protocol 112.
  • Both nodes show VIP (split-brain) — check network connectivity between nodes on the VRRP interface. Both nodes lost contact and each promoted itself to MASTER. Restore connectivity; the lower-priority node will relinquish the VIP.
  • LVS probe shows 0 active real servers — run ipvsadm -L -n to see the pool state, then check the individual real server health check scripts in Keepalived config.
  • keepalived --reload silently fails — test config with keepalived --config-test -f /etc/keepalived/keepalived.conf before reloading.

Next steps

  • SSL monitoring — if the VIP serves HTTPS, add an SSL certificate expiry monitor in Vigilmon to catch cert issues before they become outages
  • ARP monitoring — on critical failovers, verify gratuitous ARP propagation by checking MAC address tables on your switch; stale ARP caches can cause post-failover packet loss

Start monitoring your Keepalived HA infrastructure today at vigilmon.online — free, no credit card.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →