Cross-Provider High Availability: Manual Failover IP Configuration with Keepalived Between Hetzner and Vultr
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 libipset4Configuring 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.,eth0on Hetzner versusenp1s0on Vultr). Verify your network interfaces using theip addrcommand 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
fiMake 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
;;
esacSet 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 keepalivedTo 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.logStop 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.
