Keepalived is a routing software written in C that can be used to setup load balancing and high availiability for Linux machines.

NOTE: hypervisor is Debian 10 (Buster) with libvirt and qemu/kvm, virtual machines also are Debian 10 (Buster).

Keepalived configuration

Install keepalived:

$ apt install keepalived

Install nginx, it will be use to check that keepalived is actually working:

$ apt install nginx
$ systemctl enable --now nginx

Configure keepalived:

$ vi /etc/keepalived/keepalived.conf
global_defs {
  enable_script_security    # prevents tampering with the check script
  script_user root          # defines which user runs the check script

vrrp_script chk_nginx {
  script "/opt/scripts/"
  interval 2                # run script every 2 seconds
  weight 2                  # add 2 points if OK

vrrp_instance VI_1 {
  interface enp2s0          # interface to monitor
  virtual_router_id 51
  priority 101              # MASTER 101, BACKUP 100
  advert_int 1
  nopreempt                 # comment to not have the VIP go back to MASTER 
                            # -> when it comes back online
  authentication {
    auth_type PASS
    auth_pass myPass        # maximum 8 chars
  virtual_ipaddress {           # VIP (Virtual IP Address)
  track_script {

Also add a script to check if nginx is alive and well:

$ mkdir /opt/scripts
$ vi /opt/scripts/

if [ -z "`pidof nginx`" ]; then
  exit 1
$ chmod 700 /opt/scripts/
$ chown root:root /opt/scripts/

Iptables configuration

VRRP as a protocol doesn’t provide much protection against session hijacking, to make it somewhat safer a bit of iptables love might help:

-A INPUT -i <interface_name> -s <ip_of_other_machine/subnet_cidr_prefix> -d -p vrrp -j ACCEPT
-A OUTPUT -o <interface_name> -d -p vrrp -j ACCEPT

libvirt and qemu/KVM caveats

In my case I have two virtual machine each configured with one MACVTAP virtual network adapter.
Apparently libvirt MACVTAP network interfaces doesn’t actually pass all traffic going from host to guests and vice versa.
This unfortunate behavior makes it impossible for keepalived to receive packets, meaning that both machines will try to elavate themselves to MASTER status.
To avoid this conflict, add trustGuestRxFilters='yes' parameter to the virtual network adapter config:

$ virsh edit <vm_name>
    <interface type='direct' trustGuestRxFilters='yes'>