# How to Configure Floating IP for a Highly Available INFINI Gateway Deployment

> Learn to configure floating IP for a highly available INFINI Gateway deployment. Follow steps to enable the plugin, set IPs, assign priorities, and ensure a resilient setup.

- Repository: [INFINI Labs/gateway](https://github.com/infinilabs/gateway)
- Tags: how-to-guide
- Published: 2026-03-04

---

**To configure floating IP for a highly available INFINI Gateway deployment, enable the `floating_ip` plugin in [`gateway.yml`](https://github.com/infinilabs/gateway/blob/main/gateway.yml), set the virtual IP and network interface on both nodes, assign different priority values to determine the active node, and run the gateway binary as root on both machines.**

The floating IP feature in INFINI Gateway provides built-in high availability by creating a virtual IP address that automatically migrates between an active and standby gateway node. This mechanism ensures continuous client connectivity during node failures without requiring external load balancers or DNS changes. The functionality is implemented in the `floating_ip` plugin located in [`service/floating_ip/floating_ip.go`](https://github.com/infinilabs/gateway/blob/main/service/floating_ip/floating_ip.go).

## Prerequisites for Configuring Floating IP in INFINI Gateway

### Network and Permission Requirements

Root or sudo privileges are mandatory because the plugin must add and remove IP aliases and send gratuitous ARP packets. The plugin explicitly checks for root access in `FloatingIPPlugin.Start()` using `util.HasSudoPermission()` and aborts with an error if not running as root.

Both gateway nodes must reside on the same Layer 2 network segment to allow MAC address and ARP visibility between hosts. Additionally, firewall rules must permit UDP traffic on `224.3.2.2:7654` for multicast status broadcasts and TCP port `61111` for echo health checks.

### Configuration Consistency Between Nodes

The `floating_ip` configuration section must be identical on both nodes except for the `priority` field. Consistent settings for `ip`, `interface`, `netmask`, `echo.port`, and `broadcast.binding` ensure both nodes agree on the virtual address parameters and communication channels.

## Step-by-Step Floating IP Configuration

### 1. Edit gateway.yml on Both Nodes

Add the `floating_ip` configuration block to [`gateway.yml`](https://github.com/infinilabs/gateway/blob/main/gateway.yml) (around line 77 in the default configuration file):

```yaml
floating_ip:
  enabled: true
  netmask: 255.255.255.0
  ip: 10.0.0.234
  interface: eth0
  local_ip: 10.0.0.10
  priority: 100
  forced_by_priority: false
  echo:
    port: 61111
    dial_timeout_in_ms: 1000
    timeout_in_ms: 5000
  broadcast:
    binding: 224.3.2.2:7654

```

Key parameters include:

- `ip`: The virtual address that clients will use to connect to the gateway cluster.
- `interface`: The network interface that will host the IP alias (e.g., `eth0`, `ens33`).
- `priority`: Determines active node election; higher values take precedence.
- `echo.port`: TCP port for health check echo service.
- `broadcast.binding`: Multicast address for node status communication.

### 2. Ensure Root Privileges

The gateway binary must run as root to manage network interfaces. The plugin validates this in `FloatingIPPlugin.Start()`:

```go
if !util.HasSudoPermission() {
    return errors.New("root privilege are required to use floating_ip.")
}

```

Start the service using sudo or configure a systemd service to run as the root user.

### 3. Configure Node Priority for Active/Standby Election

On the second node, modify only the `priority` field to a different value (e.g., `200`):

```yaml
floating_ip:
  priority: 200

```

The node with the higher priority becomes the active node. If `forced_by_priority` is set to `true`, a node with higher priority will force a switch when it comes online, even if another node is currently active.

### 4. Start INFINI Gateway and Verify Operation

Start the gateway on both nodes:

```bash
sudo ./bin/gateway

```

During startup, the plugin executes several initialization steps in `FloatingIPPlugin.Start()`:

1. Parses configuration using `env.ParseConfig("floating_ip", &floatingIPConfig)`.
2. Auto-detects missing network parameters using `util.GetPublishNetworkDeviceInfo`.
3. Starts the heartbeat echo server via `heartbeat.StartServer` on the configured `echo.port`.

Verify the active node has claimed the floating IP:

```bash
ip addr show dev eth0 | grep 10.0.0.234

```

Monitor gratuitous ARP announcements (sent every 10 seconds):

```bash
sudo tcpdump -i eth0 arp and host 10.0.0.234

```

### 5. Test Failover Between Gateway Nodes

Simulate a failure on the active node to validate HA behavior:

```bash

# On active node: block echo port to simulate failure

sudo iptables -A INPUT -p tcp --dport 61111 -j DROP

```

The standby node detects the failure through its heartbeat client (`heartbeat.New()`). When the echo service stops responding, the standby node invokes `SwitchToActiveMode()`, which:

1. Creates the IP alias on the local interface using `util.SetupAlias`.
2. Begins sending gratuitous ARP packets every 10 seconds.
3. Starts broadcasting active status via multicast.

Verify the IP has migrated to the standby node:

```bash

# On the new active node (formerly standby)

ip addr show dev eth0 | grep 10.0.0.234

```

Remove the firewall rule on the recovered node to return it to service:

```bash
sudo iptables -D INPUT -p tcp --dport 61111 -j DROP

```

## Understanding the Floating IP State Machine

The HA mechanism relies on a state machine implemented in [`service/floating_ip/floating_ip.go`](https://github.com/infinilabs/gateway/blob/main/service/floating_ip/floating_ip.go). When the plugin starts, `StateMachine()` performs an initial health check to determine whether to become active or standby.

**Active Mode** (`SwitchToActiveMode()`):
- Creates an IP alias on the configured interface using `util.SetupAlias`.
- Starts a goroutine to send gratuitous ARP announcements every 10 seconds.
- Begins broadcasting active status via multicast to `224.3.2.2:7654`.

**Standby Mode** (`SwitchToStandbyMode()`):
- Removes any existing IP alias using `util.DisableAlias`.
- Starts a heartbeat client (`heartbeat.New()`) that connects to the active node's echo port (default 61111).
- Listens for multicast broadcasts to track the current active node's priority and status.

## Summary

- **Enable** the `floating_ip` plugin in [`gateway.yml`](https://github.com/infinilabs/gateway/blob/main/gateway.yml) on both nodes by setting `enabled: true`.
- **Configure** identical virtual IP, interface, netmask, and multicast settings on both nodes, varying only the `priority` value to control active node election.
- **Run** the INFINI Gateway binary as root to allow network interface manipulation and ARP broadcasting.
- **Verify** the active node creates the IP alias and sends gratuitous ARP every 10 seconds, while the standby monitors via TCP echo on port 61111.
- **Test** failover by blocking the echo port on the active node; the standby should automatically promote itself and acquire the floating IP through `SwitchToActiveMode()`.

## Frequently Asked Questions

### What is the default multicast address used for floating IP communication?

INFINI Gateway uses `224.3.2.2:7654` as the default multicast address for broadcasting node status between gateway instances. This address is configured in the `broadcast.binding` field of the `floating_ip` section in [`gateway.yml`](https://github.com/infinilabs/gateway/blob/main/gateway.yml). Both nodes must have network connectivity to this multicast address for proper active/standby election and health monitoring.

### Why does the floating IP plugin require root privileges?

The plugin requires root privileges because it must create and remove IP aliases on network interfaces using `util.SetupAlias` and `util.DisableAlias`, and send gratuitous ARP packets to announce the virtual IP address to the network. The `FloatingIPPlugin.Start()` function explicitly checks for root access using `util.HasSudoPermission()` and returns an error if the process lacks sufficient privileges.

### How does the standby node detect that the active node has failed?

The standby node runs a heartbeat client (`heartbeat.New()`) that periodically attempts to connect to the active node's echo service on the configured TCP port (default 61111). If the connection fails or times out according to the `dial_timeout_in_ms` and `timeout_in_ms` settings, the standby node receives a failure signal through the `aliveChan` channel. This triggers `SwitchToActiveMode()`, causing the standby node to promote itself to active status and acquire the floating IP address.

### Can I use floating IP with more than two gateway nodes?

The floating IP implementation in [`service/floating_ip/floating_ip.go`](https://github.com/infinilabs/gateway/blob/main/service/floating_ip/floating_ip.go) is designed primarily for an active-standby pair architecture. While the multicast discovery mechanism can theoretically see multiple nodes, the state machine logic (`StateMachine()`, `SwitchToActiveMode()`, `SwitchToStandbyMode()`) is optimized for two-node failover scenarios where one node is active and the other is standby. For deployments requiring more than two nodes, consider using external load balancers or clustering solutions rather than the built-in floating IP mechanism.