This guide will walk you through setting up Virtual Router Redundancy Protocol (VRRP) using keepalived
on two Debian servers to achieve high availability for your Apache web service.
debian-master
192.168.1.10
eth0
(or your primary network interface)debian-backup
192.168.1.20
eth0
192.168.1.1
(Clients will connect to this IP)apache2
package) should be installed and configured on both servers. Ensure your web content is synchronized between them (e.g., via rsync
, csync2
, or a shared storage solution).keepalived
on Both DevicesOn both debian-master
and debian-backup
, open a terminal and run:
sudo apt update
sudo apt install keepalived -y
keepalived
on debian-master
(Master)Backup the original configuration file (optional but recommended):
sudo cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
Edit the configuration file:
sudo nano /etc/keepalived/keepalived.conf
Add the following content (delete existing content or comment it out).
Important: Replace eth0
with your actual network interface name if different. Adjust mysecretpassword
to a strong, unique password.
# Global Configuration (Optional)
global_defs {
router_id LVS_DEBIAN_MASTER
# Uncomment and configure if you want email alerts
# notification_email {
# admin@example.com
# }
# notification_email_from keepalived@example.com
# smtp_server 127.0.0.1
# smtp_connect_timeout 30
}
# Health check script for Apache
vrrp_script chk_apache {
script "systemctl is-active apache2" # Checks if the apache2 service is active
interval 2 # Check every 2 seconds
weight 2 # Increase priority by 2 if the script succeeds
fall 2 # Number of failures before state change (e.g., if Apache stops 2 times)
rise 2 # Number of successes before state change (e.g., if Apache starts 2 times)
}
# VRRP Instance for the Virtual IP
vrrp_instance VI_1 {
state MASTER # This device is the master initially
interface eth0 # Your primary network interface (e.g., ens18, enp0s3)
virtual_router_id 51 # Unique ID for this VRRP instance (1-255). Must be same on both servers.
priority 100 # Higher priority means it will be master (1-254, 255 is for CARP).
advert_int 1 # Advertisement interval in seconds (how often heartbeats are sent).
authentication {
auth_type PASS
auth_pass mysecretpassword # Simple password for VRRP authentication. Must be same on both servers.
}
virtual_ipaddress {
192.168.1.1/24 # The Virtual IP address. Use CIDR notation.
}
track_script {
chk_apache # Track the custom script for Apache's health
}
# Custom scripts to run on state changes (optional but recommended for alerts/actions)
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
notify_stop "/etc/keepalived/notify.sh STOP"
# smtp_alert # Enable email alerts if global_defs are configured
}
global_defs
: Optional block for global settings like router_id
and email alerts.vrrp_script chk_apache
: Defines a health check. systemctl is-active apache2
checks if the Apache service is running. If it fails, keepalived
will reduce the server's priority, potentially triggering a failover. fall
and rise
provide robustness against flapping.vrrp_instance VI_1
: Defines the VRRP group.state MASTER
: This server will attempt to become the master.interface eth0
: The network interface keepalived
will monitor and add the VIP to.virtual_router_id 51
: A unique ID for this specific VRRP group. All servers in the group must use the same ID.priority 100
: The priority for this server. Higher priority wins.advert_int 1
: How frequently VRRP packets are sent.authentication
: Crucial for security. Use PASS
for simple password authentication. The password must match across all VRRP group members.virtual_ipaddress
: The actual IP address that clients will use to access Apache.track_script chk_apache
: Links the vrrp_script
to this VRRP instance, so its health check influences the server's priority.notify_master
, notify_backup
, notify_fault
, notify_stop
: These allow keepalived
to execute custom shell scripts (notify.sh
) whenever the server's state in the VRRP instance changes.Create the notify.sh
script (optional but highly recommended for logging/alerts):
sudo nano /etc/keepalived/notify.sh
Add the following content:
#!/bin/bash
TYPE=$1 # e.g., "MASTER", "BACKUP", "FAULT", "STOP"
# NAME=$2 # Not used in this simple script but available (e.g., "VI_1")
STATE=$2 # Current state
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
case $STATE in
"MASTER")
echo "$TIMESTAMP: VRRP State Change: Master for VRRP instance on $(hostname) ($TYPE). VIP: $(ip addr show eth0 | grep -oP 'inet (\d+\.\d+\.\d+\.\d+)/24' | awk '{print $2}' | cut -d'/' -f1)" | systemd-cat -t keepalived-notify
# Add any other master-specific actions here, e.g., starting other services
;;
"BACKUP")
echo "$TIMESTAMP: VRRP State Change: Backup for VRRP instance on $(hostname) ($TYPE)." | systemd-cat -t keepalived-notify
;;
"FAULT")
echo "$TIMESTAMP: VRRP State Change: Fault state for VRRP instance on $(hostname) ($TYPE). Investigate issues!" | systemd-cat -t keepalived-notify
# Consider sending email alert here if not using smtp_alert
;;
"STOP")
echo "$TIMESTAMP: VRRP State Change: Keepalived stopping for VRRP instance on $(hostname) ($TYPE)." | systemd-cat -t keepalived-notify
;;
*)
echo "$TIMESTAMP: VRRP State Change: Unknown state $STATE for VRRP instance on $(hostname) ($TYPE)." | systemd-cat -t keepalived-notify
;;
esac
exit 0
Make the script executable:
sudo chmod +x /etc/keepalived/notify.sh
keepalived
on debian-backup
(Backup)Backup the original configuration file:
sudo cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
Edit the configuration file:
sudo nano /etc/keepalived/keepalived.conf
Add the following content. Notice the state
is BACKUP
and priority
is lower than the master.
# Global Configuration (Optional)
global_defs {
router_id LVS_DEBIAN_BACKUP
# notification_email {
# admin@example.com
# }
# notification_email_from keepalived@example.com
# smtp_server 127.0.0.1
# smtp_connect_timeout 30
}
# Health check script for Apache
vrrp_script chk_apache {
script "systemctl is-active apache2" # Checks if the apache2 service is active
interval 2
weight 2
fall 2
rise 2
}
# VRRP Instance for the Virtual IP
vrrp_instance VI_1 {
state BACKUP # This device is the backup initially
interface eth0 # Your primary network interface
virtual_router_id 51 # Must be the same as the master
priority 90 # Lower priority than the master (e.g., 90 vs 100)
advert_int 1
authentication {
auth_type PASS
auth_pass mysecretpassword # Must be the same as the master
}
virtual_ipaddress {
192.168.1.1/24 # The Virtual IP address
}
track_script {
chk_apache
}
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
notify_stop "/etc/keepalived/notify.sh STOP"
# smtp_alert
}
Create the same notify.sh
script on the backup server:
sudo nano /etc/keepalived/notify.sh
Add the same content as before and make it executable:
#!/bin/bash
TYPE=$1
STATE=$2
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
case $STATE in
"MASTER")
echo "$TIMESTAMP: VRRP State Change: Master for VRRP instance on $(hostname) ($TYPE). VIP: $(ip addr show eth0 | grep -oP 'inet (\d+\.\d+\.\d+\.\d+)/24' | awk '{print $2}' | cut -d'/' -f1)" | systemd-cat -t keepalived-notify
;;
"BACKUP")
echo "$TIMESTAMP: VRRP State Change: Backup for VRRP instance on $(hostname) ($TYPE)." | systemd-cat -t keepalived-notify
;;
"FAULT")
echo "$TIMESTAMP: VRRP State Change: Fault state for VRRP instance on $(hostname) ($TYPE). Investigate issues!" | systemd-cat -t keepalived-notify
;;
"STOP")
echo "$TIMESTAMP: VRRP State Change: Keepalived stopping for VRRP instance on $(hostname) ($TYPE)." | systemd-cat -t keepalived-notify
;;
*)
echo "$TIMESTAMP: VRRP State Change: Unknown state $STATE for VRRP instance on $(hostname) ($TYPE)." | systemd-cat -t keepalived-notify
;;
esac
exit 0
sudo chmod +x /etc/keepalived/notify.sh
keepalived
on Both DevicesOn both debian-master
and debian-backup
, run:
sudo systemctl enable keepalived
sudo systemctl start keepalived
Check keepalived
service status on both machines:
sudo systemctl status keepalived
Active: active (running)
. Look for any error messages in the output.Check for the Virtual IP on the Master:
On debian-master
, run:
ip addr show eth0 # Replace eth0 with your interface name
inet 192.168.1.1/24
configured on eth0
(or sometimes as eth0:vrrp
).On debian-backup
, you should not see the VIP initially when the master is healthy.
Check the keepalived
logs for state transitions:
On both machines, check the journal logs for keepalived
messages:
sudo journalctl -u keepalived -f
Transition to MASTER state
on debian-master
and Transition to BACKUP state
on debian-backup
. You should also see messages related to chk_apache
script execution.Test Failover (Apache Service Failure):
debian-master
(the current master), stop the Apache service:
sudo systemctl stop apache2
sudo journalctl -u keepalived -f
on both servers. You should see debian-master
reduce its priority due to chk_apache
failing, and debian-backup
should transition to MASTER state.debian-backup
, check ip addr show eth0
. The VIP 192.168.1.1
should now be present.http://192.168.1.1
. It should now be served by debian-backup
.sudo systemctl start apache2
ip addr show eth0
on both to confirm the VIP moves back.Test Failover (Server Failure):
debian-master
, gracefully shut down the server or simply stop keepalived
:
sudo systemctl stop keepalived
# Or sudo shutdown -h now
debian-backup
.keepalived
or reboot the server. The master should reclaim the VIP once it's fully operational.When troubleshooting VRRP with Apache, these commands are invaluable:
Check keepalived
service status:
sudo systemctl status keepalived
Active: active (running)
. Any error messages like "Failed to load configuration" indicate syntax issues.View keepalived
detailed logs:
sudo journalctl -u keepalived -f
keepalived
actions, state changes, and script execution results.Transition to MASTER state
or Transition to BACKUP state
.notify.sh
script.chk_apache
script (script chk_apache succeeded
or failed
).Check network interface configuration (especially for the VIP):
ip addr show eth0 # Replace eth0 with your network interface
inet 192.168.1.1/24
should appear on the active master.Ping the Virtual IP from a third machine:
ping 192.168.1.1
Check network connectivity between VRRP nodes (physical IPs):
ping 192.168.1.10 # From backup to master's physical IP
ping 192.168.1.20 # From master to backup's physical IP
Verify Apache service status:
sudo systemctl status apache2
keepalived
. This is what chk_apache
checks.Active: active (running)
.Check for keepalived
process:
pgrep keepalived # Returns PID if running
ps aux | grep keepalived
Verify firewall rules (if any - ufw
or iptables
):
VRRP uses IP protocol number 112 (not TCP/UDP port). Ensure your firewall allows this protocol.
ufw
:
sudo ufw status verbose
sudo ufw allow vrrp
sudo ufw reload
iptables
:
sudo iptables -L -n -v
sudo iptables -A INPUT -p 112 -j ACCEPT
# If you save iptables rules, remember to persist them
Check sysctl
settings (IP Non-local Bind):
keepalived
requires net.ipv4.ip_nonlocal_bind
to be enabled (1
). It's usually default, but worth checking.
sysctl net.ipv4.ip_nonlocal_bind
net.ipv4.ip_nonlocal_bind = 1
. If not, enable it permanently:
echo "net.ipv4.ip_nonlocal_bind = 1" | sudo tee /etc/sysctl.d/99-keepalived.conf
sudo sysctl -p /etc/sysctl.d/99-keepalived.conf
Use tcpdump
to capture VRRP traffic:
This is an advanced step, but very useful for deep network debugging.
sudo tcpdump -i eth0 host 224.0.0.18 and proto 112 -v
224.0.0.18
is the standard multicast address for VRRP.By following these steps, you should have a robust and highly available Apache setup using VRRP. Remember to thoroughly test your failover scenarios in a controlled environment before deploying to production.