To Serve Admin

A practical cookbook for people who run servers

Linux · DevOps · Networking · Homelab · Cloud · Game Servers · AI Infra

§ 1.1 Guide

Active-Passive Internet Failover with BGP and Keepalived

FIG. 1 — tsa-hero-81
YieldYour home lab automatically switches to a backup ISP when the primary connection fails.

Single-ISP connectivity creates a single point of failure (SPOF) for your entire network edge. If your upstream provider experiences a routing issue, fiber cut, or equipment failure, your homelab is unreachable from the outside world. Active-passive failover using Border Gateway Protocol (BGP) and Keepalived eliminates this risk by allowing two separate ISP connections to advertise the same public IP range. Only the active link announces the route; the passive link holds it in reserve. When the active link fails, BGP withdraws the route, and the passive link announces it, shifting traffic seamlessly.

This approach relies on your ISP’s willingness to accept BGP peering. Most residential providers do not. This guide assumes you have negotiated peering with at least one provider, or are using a datacenter-grade connection that supports it.

Why Single-ISP Connectivity Is a Risk

A single upstream link means that any failure on that path—provider-side hardware failure, BGP route leak, or physical line cut—results in total loss of external connectivity. Internal LAN services remain up, but remote access, DNS resolution for external clients, and any service dependent on public IP reachability fail.

For homelab operators, this is not just an inconvenience; it breaks automation pipelines, remote management, and public-facing services. While internal redundancy (like a second switch or storage array) helps with local availability, it does nothing for upstream reachability. BGP-based failover is the standard method for eliminating this SPOF at the network edge.

Note: This article does not cover internal LAN redundancy, storage HA, or application-level clustering. Those are separate concerns.

Prerequisites: BGP Peering and Interface Setup

Before configuring failover, you must have:

  • Two separate ISP connections with distinct public IP ranges.
  • BGP peering established with at least one provider (ideally both). This requires your ISP to provide:
    • Their AS number.
    • Their BGP peer IP address.
    • The subnet they expect you to announce.
  • A router or firewall that supports BGP. Common choices include pfSense, OpenWrt, or a Linux box running FRRouting (FRR).
  • Two network interfaces, one per ISP, each with a public IP assigned.

If your ISP does not support BGP, you cannot implement this failover method. You will need to rely on static IP failover with a provider that supports it, or use a different architecture entirely.

The source material for this setup is a general index for a homelab project, not a technical tutorial. It does not contain specific BGP or Keepalived configurations. The following steps are standard practice for this architecture, grounded in common homelab implementations.

Configuring Keepalived for VIP Management

Keepalived is a userspace daemon that manages a Virtual IP (VIP) and monitors the health of the underlying network interfaces. In an active-passive BGP setup, Keepalived does not directly handle BGP announcements. Instead, it manages the local interface state and triggers BGP route withdrawal/announcement via a script or by toggling the interface.

However, a more robust and common approach is to let BGP itself handle the failover logic. Keepalived is often used to monitor the health of the active ISP link and trigger a route withdrawal when the link is down.

For this guide, we will use Keepalived to monitor the active ISP’s gateway and trigger a BGP route withdrawal. The passive ISP’s BGP daemon will then announce the route.

Example Keepalived configuration (/etc/keepalived/keepalived.conf):

vrrp_script chk_isp1 {
    script "/usr/bin/ping -c 3 -W 1 192.168.1.1"
    interval 2
    weight -20
    fall 3
    rise 3
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass secret
    }
    virtual_ipaddress {
        203.0.113.10/32
    }
    track_script {
        chk_isp1
    }
}

In this example:

  • chk_isp1 pings the ISP1 gateway (192.168.1.1).
  • If three consecutive pings fail, the VRRP instance drops priority, triggering a failover.
  • The VIP (203.0.113.10) is the public IP you want to failover.

Note: This is a simplified example. In a real BGP setup, the VIP is often the first IP in the announced subnet, and BGP handles the actual route announcement. Keepalived’s role is to detect failure and signal the BGP daemon to withdraw the route.

Integrating BGP with Keepalived for Failover

The integration point is critical. Keepalived must be able to trigger BGP route withdrawal. This is typically done via a notify script in the VRRP configuration.

Example notify script (/etc/keepalived/notify-bgp.sh):

#!/bin/bash
case "$1" in
    MASTER)
        # Activate BGP announcement for this interface
        vtysh -c "configure terminal" -c "router bgp 65001" -c "network 203.0.113.0/24"
        ;;
    BACKUP)
        # Withdraw BGP announcement
        vtysh -c "configure terminal" -c "router bgp 65001" -c "no network 203.0.113.0/24"
        ;;
esac

Add this to your Keepalived configuration:

vrrp_instance VI_1 {
    # ... other settings ...
    notify_master "/etc/keepalived/notify-bgp.sh MASTER"
    notify_backup "/etc/keepalived/notify-bgp.sh BACKUP"
}

This script uses vtysh (FRRouting’s CLI) to add or remove the network from the BGP routing table. When Keepalived detects a failure and transitions to BACKUP, it withdraws the route. The passive ISP’s BGP daemon, which has the route in its table but was not announcing it, will now announce it.

Testing Failover and Failback Scenarios

Testing is mandatory. A failover configuration that has not been tested is a broken configuration.

  1. Failover Test:

    • On the active node, disable the ISP interface: ip link set eth0 down.
    • Wait for Keepalived to detect the failure (3 pings × 1 second = ~3 seconds).
    • Verify that the VIP has moved to the passive node: ip addr show eth0 on the passive node.
    • Verify that BGP has withdrawn the route on the active node and announced it on the passive node: vtysh -c "show ip bgp".
    • Test external connectivity to the VIP.
  2. Failback Test:

    • Re-enable the ISP interface on the original active node: ip link set eth0 up.
    • Wait for Keepalived to detect the recovery.
    • Verify that the VIP has moved back to the original node.
    • Verify that BGP has re-announced the route on the original node and withdrawn it on the passive node.

If failback does not occur, check the notify script and BGP daemon logs. Common issues include:

  • The notify script not having execute permissions.
  • FRRouting not running or not configured to accept vtysh commands.
  • BGP session not established with the passive ISP.

Common Pitfalls and Monitoring

Pitfall 1: Split-brain.
If both nodes believe they are MASTER, both will announce the route, causing routing loops and packet loss. Keepalived’s VRRP protocol is designed to prevent this, but misconfiguration (e.g., same virtual_router_id with different priorities) can cause it. Ensure virtual_router_id is unique per VRRP instance.

Pitfall 2: BGP session instability.
If the BGP session with the passive ISP is flaky, failover may not work when needed. Monitor BGP session state: vtysh -c "show ip bgp summary".

Pitfall 3: Keepalived not triggering.
If the chk_isp1 script fails to detect a downed link, failover will not occur. Test the script manually: /usr/bin/ping -c 3 -W 1 192.168.1.1. Ensure the gateway IP is correct.

Monitoring:

  • Monitor Keepalived logs: journalctl -u keepalived.
  • Monitor BGP session state: vtysh -c "show ip bgp summary".
  • Monitor VIP location: ip addr show eth0 on both nodes.
  • Use an external monitoring service (e.g., UptimeRobot) to ping the VIP from the internet. This is the only true test of external reachability.

Limitations:

  • This setup requires BGP peering with your ISP. If your ISP does not support BGP, this method is not viable.
  • The source material does not provide statistics on ISP outage frequency. You must determine your own risk tolerance.
  • The source material does not mention pfSense, OpenWrt, or Debian/Ubuntu specifically. The examples here use FRRouting on a Linux system. Adapt the notify script and BGP commands to your router OS.
  • This is not a high-availability setup. There will be a brief period of downtime during failover (typically 3–10 seconds). If you require zero-downtime, consider Anycast or a load balancer with health checks.

For further reading on internal LAN redundancy or storage HA, see a separate article on those topics. This article is strictly focused on upstream internet failover.

§ adj. Did this recipe work for you?

§ notes Reader notes

LEAVE A NOTE — field-tested feedback only, please

notes are reviewed before publication. No spam, no ads, no “first”-type nonsense.