← Back to DevBytes

IPVS Load Balancing: Complete Setup and Configuration Guide

What is IPVS?

IPVS (IP Virtual Server) is a kernel‑level load balancer that runs directly inside the Linux network stack. It is the core engine of the Linux Virtual Server (LVS) project and operates purely at Layer 4 (the transport layer), distributing TCP, UDP, and SCTP traffic across a pool of backend real servers. Unlike user‑space proxies such as HAProxy or Nginx, IPVS makes forwarding decisions inside the kernel via Netfilter hooks, which gives it exceptional throughput and near‑zero added latency.

IPVS is not a separate daemon—it is a set of kernel modules (ip_vs, ip_vs_rr, ip_vs_wrr, etc.) that are managed from userspace with the ipvsadm command. Once configured, incoming requests hit a virtual service (a single IP address and port), and IPVS rewrites or forwards the packets to one of many real servers according to a scheduling algorithm of your choice.

Why IPVS Matters

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

IPVS offers a unique combination of raw speed, massive scalability, and deep integration with the Linux kernel. It matters for several reasons:

If you need a fast, reliable Layer 4 load balancer that can sit directly on a Linux host without external dependencies, IPVS is one of the best choices available.

Core Components and Concepts

Virtual Server, Real Servers, and Forwarding Methods

An IPVS configuration has three key building blocks:

NAT (Network Address Translation)

In NAT mode, the load balancer rewrites the destination IP and port of incoming packets to match the chosen real server. The real server sees the load balancer as the client, and response traffic must flow back through the load balancer. This is the simplest method to understand but puts all return traffic on the load balancer, potentially becoming a bottleneck for very high‑bandwidth responses.

Direct Routing (DR)

DR mode is the highest‑performance option. The load balancer forwards packets to the real server without altering the destination IP. Instead, the real server also holds the VIP on a loopback interface. The real server processes the request and replies directly to the client, bypassing the load balancer entirely for outbound traffic. This requires careful ARP handling so that only the load balancer answers ARP requests for the VIP.

IP Tunneling (TUN)

Tunneling is similar to DR but encapsulates the original packet inside an IP‑IP tunnel. It allows the real servers to be on a different network from the load balancer. Like DR, the real server must have the VIP configured on a loopback interface and reply directly to the client. This mode is less common but useful when geographically distributing backends.

Scheduling Algorithms

IPVS supports many scheduling algorithms, configured per virtual service:

Prerequisites and Installation

IPVS is available in every modern Linux kernel. You only need to ensure the relevant modules are loaded and install the ipvsadm management tool.

Verify that IPVS modules are available (they usually are by default):

lsmod | grep ip_vs
# If no output, load them manually:
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_lc

Install ipvsadm on Debian/Ubuntu:

sudo apt update
sudo apt install ipvsadm

On RHEL/CentOS/Fedora:

sudo dnf install ipvsadm   # or yum install ipvsadm

Enable IP forwarding (essential for NAT mode, and useful for DR/TUN if the load balancer routes traffic):

sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf

Setting Up IPVS: Step‑by‑Step

NAT Mode Configuration

NAT mode is the easiest to set up. The load balancer sits between clients and real servers, rewriting destination addresses. This example uses:

First, configure the VIP on the load balancer:

sudo ip addr add 192.168.1.100/24 dev eth0   # external interface

Enable IP forwarding (already done above). Then create the virtual service and add real servers:

# Add a virtual service for HTTP on port 80, using round‑robin scheduling
sudo ipvsadm -A -t 192.168.1.100:80 -s rr

# Add the first real server (NAT mode is the default)
sudo ipvsadm -a -t 192.168.1.100:80 -r 10.0.0.11:80 -m

# Add the second real server
sudo ipvsadm -a -t 192.168.1.100:80 -r 10.0.0.12:80 -m

# Enable the virtual service (start accepting traffic)
sudo ipvsadm -E -t 192.168.1.100:80 -s rr

The -m flag explicitly selects masquerading (NAT). If you omit it, ipvsadm defaults to NAT mode anyway. Real servers should have their default gateway set to the load balancer’s internal IP (10.0.0.1) so that response traffic returns through the load balancer.

To verify:

sudo ipvsadm -L -n

Direct Routing (DR) Mode Configuration

DR mode offers the highest performance because the real servers reply directly to clients. The load balancer and all real servers share the same VIP. Only the load balancer responds to ARP requests for the VIP; real servers must ignore ARP for that address. This example uses:

On the load balancer:

# Add the VIP on the external interface (e.g., eth0)
sudo ip addr add 192.168.1.100/24 dev eth0

# Create the virtual service with DR (gateway, -g) mode
sudo ipvsadm -A -t 192.168.1.100:80 -s wrr

# Add real servers with -g (direct routing)
sudo ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.11:80 -g -w 2
sudo ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.12:80 -g -w 1

The -g flag indicates DR (gateway) mode. The -w sets a weight for weighted round‑robin.

On every real server: configure the VIP on the loopback interface and suppress ARP responses.

# Add VIP to loopback (with netmask 255.255.255.255 to avoid subnet conflicts)
sudo ip addr add 192.168.1.100/32 dev lo

# Prevent the real server from answering ARP for the VIP
echo 1 | sudo tee /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 | sudo tee /proc/sys/net/ipv4/conf/all/arp_announce

# Make these settings persistent
echo "net.ipv4.conf.all.arp_ignore = 1" | sudo tee -a /etc/sysctl.conf
echo "net.ipv4.conf.all.arp_announce = 2" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Alternatively, you can use arptables to drop ARP replies for the VIP on real servers, but the sysctl approach is simpler and sufficient for most environments.

Now clients can reach the VIP, the load balancer forwards the TCP SYN to one real server, and that real server answers the client directly. Verify with:

sudo ipvsadm -L -n --stats

Tunneling (TUN) Mode – Brief Overview

Tunneling mode uses IP‑IP encapsulation. It is configured similarly to DR, but uses the -i flag instead of -g and requires the ipip kernel module on both the load balancer and real servers. Real servers still configure the VIP on loopback and suppress ARP. The setup command looks like:

sudo ipvsadm -A -t 192.168.1.100:80 -s lc
sudo ipvsadm -a -t 192.168.1.100:80 -r 10.1.1.11:80 -i   # -i for IPIP tunneling

Because TUN adds overhead and is rarely needed unless backends are on a different LAN, DR is almost always preferred for direct‑reply architectures.

Managing IPVS Rules and Persistence

Viewing and Saving Configuration

To inspect the current IPVS table:

sudo ipvsadm -L -n           # numeric output
sudo ipvsadm -L -n --stats    # with traffic statistics
sudo ipvsadm -L -n --rate     # connection rate

Save the rules for restoration after reboot (rules are not persistent by default):

sudo ipvsadm -S > /etc/ipvsadm.rules

Restore them:

sudo ipvsadm -R < /etc/ipvsadm.rules

Many distributions provide a systemd service or init script that automatically restores rules from /etc/ipvsadm.rules when the ipvsadm package is installed.

Connection Persistence

IPVS can pin clients to the same real server for a configurable timeout using the --persistent option. This is a Layer 4 stickiness mechanism that works without cookies or application‑level tracking:

# Create a virtual service with 600-second persistence
sudo ipvsadm -A -t 192.168.1.100:80 -s wlc --persistent 600

During the persistence window, all connections from the same source IP will be forwarded to the same real server. This is useful for stateful applications that store session data locally.

Firewall Marks for Multi‑Port Services

Sometimes you want to load‑balance a service that spans multiple ports (e.g., FTP with control and data channels) as a single entity. IPVS allows grouping ports using a firewall mark (a netfilter mark set via iptables). The mark ties together different TCP/UDP streams.

# Mark packets destined to ports 21 and 20 with mark 80
sudo iptables -t mangle -A PREROUTING -d 192.168.1.100/32 -p tcp --dport 21 -j MARK --set-mark 80
sudo iptables -t mangle -A PREROUTING -d 192.168.1.100/32 -p tcp --dport 20 -j MARK --set-mark 80

# Create a virtual service based on firewall mark 80
sudo ipvsadm -A -f 80 -s rr

# Add real servers (note: no port specified, the mark handles it)
sudo ipvsadm -a -f 80 -r 192.168.1.11:0 -g
sudo ipvsadm -a -f 80 -r 192.168.1.12:0 -g

The :0 after the real server address tells IPVS to preserve the original destination port.

Advanced Configuration and Best Practices

Health Checking

IPVS itself does not perform health checks; it simply forwards packets. If a real server dies, IPVS continues to send it traffic, leading to failed connections. To avoid this, you must pair IPVS with a health‑checking framework. The most common and powerful companion is Keepalived, which we cover in the next section. Alternatively, the older ldirectord daemon can also monitor real servers and add/remove them from the IPVS table dynamically.

Connection Synchronization for High Availability

In an HA setup with two load balancers (active/standby via VRRP), you can synchronise the IPVS connection state so that failovers do not break established connections. The kernel module ip_vs_sync provides a way to replicate connection entries to a peer. Keepalived supports this natively.

# Load the sync module
sudo modprobe ip_vs_sync

Then configure Keepalived’s syncd block (shown in the Keepalived example).

Sysctl Tuning for High Load

Monitoring IPVS

Use ipvsadm -L -n --stats regularly or integrate with monitoring tools. You can also access IPVS statistics via the /proc/net/ip_vs_stats file or through Netlink. Prometheus node_exporter can expose IPVS metrics when the --collector.ipvs flag is enabled.

Integrating with Keepalived for High Availability

Keepalived provides VRRP‑based failover and built‑in health checking that directly manipulates the IPVS table. It is the de‑facto standard for building highly available LVS/IPVS load balancers. Below is a minimal but complete keepalived.conf that:

global_defs {
    router_id lb1
    vrrp_sync_group mygroup {
        group {
            vip1
        }
    }
}

vrrp_instance vip1 {
    state MASTER            # BACKUP on the standby node
    interface eth0
    virtual_router_id 51
    priority 100            # 50 on the backup
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass secret123
    }
    virtual_ipaddress {
        192.168.1.100/24 dev eth0
    }
}

# IPVS virtual server definition
virtual_server 192.168.1.100 80 {
    delay_loop 6
    lb_algo wrr
    lb_kind DR             # Use DR (NAT would be NAT)
    protocol TCP
    persistence_timeout 300

    # Real server 1 with health check
    real_server 192.168.1.11 80 {
        weight 2
        HTTP_GET {
            url {
                path /health
                status 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    # Real server 2
    real_server 192.168.1.12 80 {
        weight 1
        HTTP_GET {
            url {
                path /health
                status 200
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

# Optional connection synchronization
syncd {
    group {
        vip1
    }
}

With this configuration, Keepalived takes ownership of the IPVS rules. You no longer need to run ipvsadm manually; Keepalived builds the table according to its health‑check results. If a real server fails its health check, Keepalived removes it from the IPVS table immediately and adds it back when it recovers.

Conclusion

IPVS delivers an incredibly fast, kernel‑resident Layer 4 load balancing solution that forms the backbone of many of the world’s largest web infrastructures. By understanding its three forwarding modes (NAT, DR, and TUN), its rich set of scheduling algorithms, and how to pair it with health‑checking tools like Keepalived, you can build a load‑balancing architecture that handles millions of connections with minimal CPU overhead. Whether you are deploying a highly available edge gateway for Kubernetes services or simply need a lightweight, no‑nonsense TCP/HTTP director for a small cluster, IPVS gives you a battle‑tested, production‑ready foundation. Start with the simple NAT examples, move to DR for maximum throughput, and always combine IPVS with an active health‑check mechanism to ensure traffic only reaches live backends.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles