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:
- Kernel‑space performance – Because all load‑balancing logic runs inside the kernel, IPVS can handle millions of simultaneous connections and gigabits of throughput without context‑switching overhead or the bottlenecks inherent in user‑space proxies.
- Extremely low latency – Packets are processed directly in the network stack, adding only microseconds of delay.
- High connection capacity – IPVS maintains an internal connection tracking table that scales to millions of entries, making it ideal for services with very long‑lived connections or enormous connection concurrency.
- Multiple scheduling algorithms – Round‑Robin, Least Connections, Weighted variants, and more sophisticated algorithms (like shortest expected delay) allow you to optimise distribution for your exact workload.
- Kubernetes kube‑proxy IPVS mode – Many production Kubernetes clusters rely on IPVS to load‑balance Service traffic to pods, demonstrating its reliability at extreme scale.
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:
- Virtual Server (VIP) – A single IP address and port that clients connect to. The VIP can be bound to a physical NIC or configured as a loopback alias.
- Real Servers (RIPs) – The backend hosts that actually serve the traffic. Each real server is identified by its IP address and port.
- Forwarding method – How IPVS transports packets from the VIP to the chosen real server. The three standard methods are NAT, Direct Routing (DR), and IP Tunneling (TUN).
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:
rr– Round‑Robin: distributes connections evenly across all real servers.wrr– Weighted Round‑Robin: assigns a weight to each real server, so more capable servers receive more traffic.lc– Least‑Connections: sends new connections to the real server with the fewest active connections.wlc– Weighted Least‑Connections: combines weights with active connection counts.lblc– Locality‑Based Least‑Connections: keeps connections to the same real server while balancing load.sh– Source Hashing: uses a hash of the source IP to guarantee that a client always reaches the same real server (useful for session stickiness without persistence).
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:
- VIP: 192.168.1.100 (on the load balancer’s external interface)
- Real servers: 10.0.0.11 (web1), 10.0.0.12 (web2) on an internal network
- Load balancer internal IP: 10.0.0.1
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:
- VIP: 192.168.1.100
- Real servers: 192.168.1.11, 192.168.1.12
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
- Increase the connection tracking table size (if using NAT mode and iptables conntrack):
net.netfilter.nf_conntrack_maxandnet.netfilter.nf_conntrack_buckets. - Tune IPVS timeouts – The default IPVS connection timeout for inactive TCP connections is often 900 seconds. You can lower it to reclaim memory faster: adjust
/proc/sys/net/ipv4/vs/timeout_*(exact paths may vary by kernel version). - Disable TCP timestamps? Not usually necessary, but in some DR/TUN setups, you may need consistent timestamp behavior between the load balancer and real servers.
- Increase the IPVS connection table size – The maximum entries is controlled by
net.ipv4.vs.max_connections(ornet.ipv4.vs.conn_tab_bits). Modern kernels automatically scale it, but on extremely busy servers you might adjust it explicitly.
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:
- Uses VRRP to float the VIP between two load balancers.
- Performs HTTP health checks on real servers and removes/adds them automatically.
- Enables connection synchronization (if the sync module is loaded).
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.