Back to articles
Technology Insight

Cross-Provider High Availability: Manual Failover IP Configuration with Keepalived Between Hetzner and Vultr

May 30, 2026

Introduction to Cross-Provider High Availability

In today's digital economy, relying on a single cloud or Virtual Private Server (VPS) provider poses a significant risk to business continuity. Whether due to localized infrastructure failures, routing anomalies, or upstream network disruptions, even the most reputable providers experience downtime. To mitigate these risks, enterprise architectures are increasingly adopting multi-cloud or cross-provider high availability (HA) strategies.

This technical guide explores how to establish a robust, manual Failover IP mechanism between two distinct VPS infrastructure providers: Hetzner and Vultr. By leveraging Keepalived—a routing software based on the Virtual Router Redundancy Protocol (VRRP)—and combining it with provider-specific APIs, you can achieve seamless traffic redirection and exceptional resilience against single-provider failure.

The Core Challenge: Cross-Provider Layer 2 Limitations

Standard high-availability setups typically utilize Keepalived to automatically broadcast VRRP advertisements over a local Layer 2 network segment. When the primary server drops, the backup server assumes control of a shared Virtual IP (VIP) almost instantly. However, when deploying servers across completely independent infrastructures like Hetzner and Vultr, Layer 2 connectivity does not exist between them.

Because VRRP broadcasts cannot cross the public internet between different autonomous systems (ASNs), we cannot rely on native Layer 2 VIP migration. Instead, we must implement a manual or API-driven Failover IP mechanic. In this architecture, Keepalived acts as the health-monitoring engine. When a state transition occurs (e.g., Master to Backup), Keepalived triggers custom shell scripts that interact with DNS APIs or external BGP routing APIs to redirect public traffic to the surviving infrastructure provider.

Prerequisites and Environment Layout

Before beginning the configuration, ensure you have provisioned the following infrastructure components:

  • Primary Node (Hetzner): A cloud VPS instance running Ubuntu 22.04 LTS or Debian 12.
  • Backup Node (Vultr): A cloud VPS instance running the identical operating system version.
  • Domain & Floating Traffic Management: A public domain hosted on a DNS provider with a fast-propagating API (such as Cloudflare, Hetzner DNS, or Vultr DNS) with low TTL settings (e.g., 60 seconds), or a managed Failover IP block if routing via BGP. For the purposes of this guide, we will use an API-driven DNS routing abstraction to simulate the Failover IP handoff across providers.
  • Administrative Access: Root or sudo privileges on both instances, alongside respective API tokens for Hetzner and Vultr.

Step 1: Installing and Configuring Keepalived

First, Keepalived must be installed on both nodes. Update your package manager repositories and install the daemon by executing the following commands on both the Hetzner and Vultr instances:

sudo apt update
sudo apt install -y keepalived libipset4

Configuring the Primary Node (Hetzner)

Edit the primary Keepalived configuration file located at /etc/keepalived/keepalived.conf. If the file does not exist, create it. Since these nodes communicate over the public internet, we will configure unicast VRRP rather than multicast.

vrrp_script check_app {
    script "/usr/local/bin/check_services.sh"
    interval 2
    weight 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 101
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass Secr3tPa55w0rd
    }

    unicast_src_ip 
    unicast_peer {
        
    }

    track_script {
        check_app
    }

    notify_master "/usr/local/bin/failover_trigger.sh MASTER"
    notify_backup "/usr/local/bin/failover_trigger.sh BACKUP"
    notify_fault "/usr/local/bin/failover_trigger.sh FAULT"
}

Configuring the Backup Node (Vultr)

Mirror the configuration on your Vultr instance with appropriate modifications to the state, priority, and unicast IP structures:

vrrp_script check_app {
    script "/usr/local/bin/check_services.sh"
    interval 2
    weight 2
}

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

    authentication {
        auth_type PASS
        auth_pass Secr3tPa55w0rd
    }

    unicast_src_ip 
    unicast_peer {
        
    }

    track_script {
        check_app
    }

    notify_master "/usr/local/bin/failover_trigger.sh MASTER"
    notify_backup "/usr/local/bin/failover_trigger.sh BACKUP"
    notify_fault "/usr/local/bin/failover_trigger.sh FAULT"
}
Note on Networking interfaces: Interface names may differ between providers (e.g., eth0 on Hetzner versus enp1s0 on Vultr). Verify your network interfaces using the ip addr command prior to deploying configurations.

Step 2: Developing Health-Checking Scripts

Keepalived relies on the check_services.sh script to evaluate local system health. If your primary web application or service fails, the script returns a non-zero exit code, forcing Keepalived to transition its state. Create the script at /usr/local/bin/check_services.sh:

#!/bin/bash
# Check if Nginx or your specific service is actively running
systemctl is-active --quiet nginx
if [ $? -eq 0 ]; then
    exit 0
else
    exit 1
fi

Make the script executable: sudo chmod +x /usr/local/bin/check_services.sh.

Step 3: Implementing the API-Driven Failover Trigger

Because these cloud infrastructures cannot share a physical IP address, the failover_trigger.sh script acts as our automated coordinator. When the Hetzner node goes offline, the Vultr node transitions into the MASTER state and executes its trigger script. This script invokes external API endpoints to dynamically reroute incoming traffic to its own public IP.

Create the file at /usr/local/bin/failover_trigger.sh on both systems:

#!/bin/bash
STATE=$1
LOG_FILE="/var/log/keepalived_failover.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$DATE] Transitioning state to: $STATE" >> $LOG_FILE

case $STATE in
    "MASTER")
        echo "[$DATE] Node elected as MASTER. Updating external IP configurations..." >> $LOG_FILE
        # INSERT PROVIDER API CALLS HERE
        # Example: Curl command to update DNS records or trigger BGP routing adjustments
        ;;
    "BACKUP")
        echo "[$DATE] Node entered BACKUP state." >> $LOG_FILE
        ;;
    "FAULT")
        echo "[$DATE] Node entered FAULT state." >> $LOG_FILE
        ;;
    *)
        echo "[$DATE] Unknown state received: $STATE" >> $LOG_FILE
        exit 1
        ;;
esac

Set execution permissions: sudo chmod +x /usr/local/bin/failover_trigger.sh.

Step 4: Testing and Validating the Setup

With configurations and orchestration scripts in place, enable and start Keepalived on both systems:

sudo systemctl enable keepalived
sudo systemctl start keepalived

To validate behavior, tail the system logs or your custom log file on the backup node while simulating a failure on the primary node:

tail -f /var/log/keepalived_failover.log

Stop the Nginx service or completely shut down the Hetzner instance. Within seconds, you will observe the Vultr instance notice the absence of VRRP heartbeats, transition to MASTER, and successfully trigger your failover routine, establishing total infrastructure redundancy.

Conclusion

By abstracting Failover IP behavior into programmatic API calls triggered by automated Keepalived states, you bypass the geographical and layer constraints of standard networking. Combining Hetzner's cost-efficiency with Vultr's global reach creates an enterprise-grade disaster recovery solution that keeps your critical services accessible regardless of single-provider infrastructure events.

Cross-Provider High Availability: Manual Failover IP Configuration with Keepalived Between Hetzner and Vultr | DPTCloud