← Back to DevBytes

IPVS Load Balancing Security Hardening and Best Practices

What is IPVS Load Balancing?

IPVS (IP Virtual Server) is the transport-layer load balancing engine built directly into the Linux kernel. It intercepts incoming packets at layer 4 (TCP/UDP) and distributes them across a pool of backend servers based on configurable scheduling algorithms. Unlike reverse proxy solutions such as HAProxy or Nginx, IPVS operates at the kernel level, meaning it does not terminate connections—it forwards packets with minimal overhead, achieving near line-speed throughput and extremely low latency.

IPVS is managed through the ipvsadm userspace tool and is commonly paired with keepalived for high-availability Virtual IP (VIP) management. It supports three forwarding modes: Direct Routing (DR), Network Address Translation (NAT), and IP Tunneling (TUN). Each mode has distinct security implications that must be understood before deployment.

Why Security Hardening Matters

🚀 Deploy your AI agent in 10 minutes

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

Try it free →

By default, IPVS configurations are functional but not secure. A misconfigured IPVS setup can expose backend servers to direct internet access, allow traffic from unintended sources, or become a vector for amplification attacks. Attackers who gain access to the load balancer host can manipulate the IPVS ruleset, redirect traffic to malicious destinations, or perform ARP poisoning in DR mode setups. Hardening is therefore not optional—it is a fundamental part of deploying IPVS in production.

Key risks include:

Understanding IPVS Forwarding Modes and Their Security Profiles

Direct Routing (DR) Mode

In DR mode, the load balancer forwards packets to backend servers without modifying the source or destination IP addresses. The backend servers must have the VIP configured on a loopback interface (typically lo:0) and respond directly to the client. This mode delivers the highest performance but introduces a critical security nuance: backend servers must be prevented from answering ARP requests for the VIP, otherwise clients may bypass the load balancer entirely.

Backend servers must be hardened with ARP suppression. The following sysctl settings are mandatory on each real server:

# On each backend server, configure ARP suppression for the VIP
# Replace eth0 with the interface facing the load balancer
net.ipv4.conf.eth0.arp_ignore = 1
net.ipv4.conf.eth0.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2

# Apply immediately
sysctl -w net.ipv4.conf.eth0.arp_ignore=1
sysctl -w net.ipv4.conf.eth0.arp_announce=2
sysctl -w net.ipv4.conf.all.arp_ignore=1
sysctl -w net.ipv4.conf.all.arp_announce=2

Additionally, the VIP on the loopback interface must be configured with a netmask of /32 to prevent the kernel from considering it a local subnet route:

# Configure VIP on loopback with host mask
ip addr add 192.0.2.100/32 dev lo
# Prevent the lo interface from advertising the VIP
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce

NAT Mode

In NAT mode, the load balancer rewrites the destination IP address (and optionally the source IP) of incoming packets. Backend servers see traffic sourced from the load balancer's internal IP. This mode naturally isolates backend servers from direct client contact, but the load balancer becomes a single point of failure for connection tracking. The nf_conntrack table can overflow under high connection rates, leading to dropped packets.

Hardening NAT mode involves protecting the connection tracking infrastructure:

# Increase conntrack limits to resist exhaustion
net.netfilter.nf_conntrack_max = 262144
net.netfilter.nf_conntrack_tcp_timeout_established = 86400
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 60
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120

# Apply
sysctl -p /etc/sysctl.d/50-ipvs-conntrack.conf

IP Tunneling (TUN) Mode

TUN mode encapsulates packets using IP-in-IP tunneling. Security concerns mirror DR mode regarding ARP handling, plus additional risks from tunnel interface exposure. Tunnel interfaces should be firewalled to accept only encapsulated traffic from the load balancer's source IP.

Firewall Integration with IPVS

IPVS operates below iptables/nftables in the network stack, which means firewall rules must be carefully coordinated. A common hardening pattern is to use nftables to restrict which source IPs can reach the VIP, while IPVS handles the load distribution logic.

Example nftables ruleset to protect an IPVS VIP:

#!/usr/bin/nft -f

table inet ipvs-shield {

    # Define the VIP and allowed client subnets
    set allowed_clients {
        type ipv4_addr
        flags interval
        elements = { 203.0.113.0/24, 198.51.100.0/24 }
    }

    chain input {
        # Allow established connections for management
        ct state established,related accept

        # Restrict VIP access to allowed clients only
        ip daddr 192.0.2.100 ip saddr @allowed_clients accept
        ip daddr 192.0.2.100 tcp dport { 80, 443 } drop

        # Allow SSH only from internal management network
        tcp dport 22 ip saddr 10.0.0.0/8 accept
        tcp dport 22 drop
    }

    chain forward {
        # In DR/NAT mode, protect backend network
        ip daddr 10.0.1.0/24 ip saddr != 10.0.0.5 drop
    }
}

# Load the ruleset
nft -f /etc/nftables/ipvs-shield.conf

For DR mode, an additional critical step is to ensure the backend servers themselves have firewall rules that reject traffic destined to the VIP on the wrong interface, preventing accidental exposure:

# On each backend server with nftables
table inet backend-guard {
    chain input {
        # Block VIP traffic arriving on physical interfaces
        iif != "lo" ip daddr 192.0.2.100 drop
        # Allow VIP traffic only on loopback
        iif "lo" ip daddr 192.0.2.100 accept
    }
}

Securing the ipvsadm Management Interface

The ipvsadm command requires CAP_NET_ADMIN capability or root privileges. In production, restrict access to this tool to prevent unauthorized modification of the load balancing ruleset.

Restricting ipvsadm Access via Sudo

# /etc/sudoers.d/ipvsadm
# Allow operators to view IPVS state, but restrict modifications
%lb_operators ALL = (root) NOPASSWD: /usr/sbin/ipvsadm -L*
%lb_operators ALL = (root) NOPASSWD: /usr/sbin/ipvsadm -l*
%lb_operators ALL = (root) NOPASSWD: /usr/sbin/ipvsadm -S*
%lb_operators ALL = (root) NOPASSWD: /usr/sbin/ipvsadm --help
# Modifications require lb_admins group
%lb_admins ALL = (root) NOPASSWD: /usr/sbin/ipvsadm

Auditing IPVS Configuration Changes

Enable audit logging for any ipvsadm invocation that modifies state:

# Add audit rules for ipvsadm writes
auditctl -w /usr/sbin/ipvsadm -p x -k ipvs_modification
auditctl -w /proc/net/ip_vs -p w -k ipvs_kernel_write

# Make audit rules persistent in /etc/audit/rules.d/ipvs.rules
echo "-w /usr/sbin/ipvsadm -p x -k ipvs_modification" >> /etc/audit/rules.d/ipvs.rules
echo "-w /proc/net/ip_vs -p w -k ipvs_kernel_write" >> /etc/audit/rules.d/ipvs.rules
augenrules --load

Protecting Against SYN Floods and Connection Exhaustion

IPVS itself has built-in resilience against SYN floods because it does not maintain a half-open connection table like a reverse proxy would. However, when used with NAT mode, the kernel's connection tracking system (nf_conntrack) can become a bottleneck. The following hardening measures apply:

# /etc/sysctl.d/60-ipvs-synprotect.conf

# Enable SYN cookies to resist SYN floods
net.ipv4.tcp_syncookies = 1

# Reduce SYN_RECV timeout
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2

# Enable TCP timestamps for better connection tracking efficiency
net.ipv4.tcp_timestamps = 1

# Increase backlog to absorb bursts
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096

# Protect against TIME_WAIT exhaustion
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# Apply
sysctl -p /etc/sysctl.d/60-ipvs-synprotect.conf

For additional protection, integrate iptables rate-limiting on the VIP before traffic reaches IPVS:

# Limit incoming SYN rate to 200/second on the VIP
iptables -A INPUT -d 192.0.2.100 -p tcp --syn -m limit --limit 200/s --limit-burst 300 -j ACCEPT
iptables -A INPUT -d 192.0.2.100 -p tcp --syn -j DROP

Connection Tracking Table Hardening

When IPVS operates in NAT mode, every connection consumes a conntrack entry. Exhaustion of this table causes silent connection drops. Monitor and size the table appropriately:

# Check current conntrack usage
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# Calculate appropriate sizing:
# Expected concurrent connections × 1.3 (safety factor) = conntrack_max
# Example: 100,000 concurrent connections → set to 131072

# Set in /etc/sysctl.d/70-conntrack.conf
net.netfilter.nf_conntrack_max = 131072
net.netfilter.nf_conntrack_buckets = 32768  # max / 4 for hash table efficiency

# Reduce timeouts for faster recycling
net.netfilter.nf_conntrack_generic_timeout = 120
net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 30

# Enable conntrack helper auto-assignment only for needed protocols
# Disable automatic helpers to prevent abuse
net.netfilter.nf_conntrack_helper = 0

Monitor conntrack utilization with a simple script to alert before exhaustion:

#!/bin/bash
# Monitor conntrack utilization and alert at 80%

MAX=$(cat /proc/sys/net/netfilter/nf_conntrack_max)
CURRENT=$(cat /proc/sys/net/netfilter/nf_conntrack_count)
USAGE=$(( CURRENT * 100 / MAX ))

if [ $USAGE -gt 80 ]; then
    logger -p kern.warning "IPVS conntrack usage at ${USAGE}% (${CURRENT}/${MAX})"
fi

Securing Keepalived for High Availability

Most IPVS deployments use keepalived for VRRP-based failover. The VRRP advertisements must be authenticated and restricted to trusted interfaces.

# /etc/keepalived/keepalived.conf (security-relevant excerpt)

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1

    # Use VRRP authentication (type 2 = simple password, type 1 = IPSec AH)
    authentication {
        auth_type PASS
        auth_pass "a-strong-random-password-at-least-32-chars"
    }

    virtual_ipaddress {
        192.0.2.100/24 dev eth0
    }

    # Restrict VRRP to specific source IPs on the peer
    # Use iptables/nftables to only accept VRRP from known peers
}

# Corresponding firewall rule for VRRP multicast
# Only accept VRRP advertisements from the known peer IP
iptables -A INPUT -i eth0 -s 10.0.0.2 -d 224.0.0.18 -p vrrp -j ACCEPT
iptables -A INPUT -i eth0 -d 224.0.0.18 -p vrrp -j DROP

Preventing Split-Brain Through Network Isolation

A split-brain scenario where two load balancers both hold the VIP can cause traffic corruption. Mitigate this by ensuring VRRP traffic uses a dedicated management network or by configuring a "backup" firewall rule that blocks the VIP if the node is in BACKUP state:

# keepalived notify script to enforce VIP ownership
# /etc/keepalived/notify.sh

#!/bin/bash
TYPE=$1
NAME=$2

case "$TYPE" in
    "MASTER")
        # Enable VIP acceptance
        iptables -D INPUT -d 192.0.2.100 -j DROP 2>/dev/null
        logger "Promoted to MASTER - VIP enabled"
        ;;
    "BACKUP")
        # Block VIP traffic to prevent split-brain
        iptables -A INPUT -d 192.0.2.100 -j DROP
        logger "Demoted to BACKUP - VIP blocked"
        ;;
    "FAULT")
        iptables -A INPUT -d 192.0.2.100 -j DROP
        logger "FAULT state - VIP blocked"
        ;;
esac

Kernel Hardening Specific to IPVS

Several kernel parameters directly affect IPVS security and resilience. Apply these in a dedicated sysctl configuration file:

# /etc/sysctl.d/80-ipvs-hardening.conf

# Disable IP forwarding on non-router interfaces
net.ipv4.ip_forward = 1  # Only on interfaces that need it
net.ipv4.conf.all.forwarding = 1
net.ipv4.conf.default.forwarding = 0

# Prevent source-routed packets from bypassing routing decisions
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Drop ICMP redirects to prevent routing table manipulation
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0

# Ignore bogus ICMP errors
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Reverse path filtering prevents IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Protect against martian packets (unroutable source addresses)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Disable IP dynamic address space features unless needed
net.ipv4.ip_dynaddr = 0

# Apply
sysctl -p /etc/sysctl.d/80-ipvs-hardening.conf

Monitoring and Intrusion Detection

Continuous monitoring of IPVS state is essential to detect unauthorized changes or anomalous traffic patterns. The /proc/net/ip_vs and /proc/net/ip_vs_stats files expose real-time metrics that can be scraped.

Detecting Unauthorized IPVS Rule Changes

#!/bin/bash
# Monitor IPVS ruleset checksum and alert on changes
# Run via cron every minute

EXPECTED_CHECKSUM_FILE="/var/lib/ipvs/expected_checksum"
CURRENT_RULES=$(ipvsadm -S -n | md5sum | awk '{print $1}')

if [ ! -f "$EXPECTED_CHECKSUM_FILE" ]; then
    echo "$CURRENT_RULES" > "$EXPECTED_CHECKSUM_FILE"
    exit 0
fi

EXPECTED=$(cat "$EXPECTED_CHECKSUM_FILE")
if [ "$CURRENT_RULES" != "$EXPECTED" ]; then
    logger -p kern.alert "CRITICAL: IPVS ruleset changed! Current: $CURRENT_RULES, Expected: $EXPECTED"
    # Send alert via your monitoring system
fi

Exporting IPVS Metrics for Prometheus

Use the ipvsadm stats output to feed monitoring systems:

# Extract per-service connection statistics
ipvsadm -L -n --stats --rate

# Example output parsing script for Prometheus textfile collector
#!/bin/bash
# Write IPVS metrics to /var/lib/node_exporter/textfile_collector/ipvs.prom

OUTPUT="/var/lib/node_exporter/textfile_collector/ipvs.prom"
TEMP=$(mktemp)

ipvsadm -L -n --stats | awk '
/^TCP|^UDP/ {
    # Parse VIP:Port -> RealServer:Port
    vip_port=$2; rs_ip=$3; rs_port=$4
}
/^  ->/ {
    gsub(/[^0-9]/, " ", $0)
    split($0, vals)
    print "ipvs_connections_total{vip=\""vip_port"\",backend=\""rs_ip":"rs_port"\"} " vals[1]
    print "ipvs_incoming_packets_total{vip=\""vip_port"\",backend=\""rs_ip":"rs_port"\"} " vals[2]
    print "ipvs_outgoing_packets_total{vip=\""vip_port"\",backend=\""rs_ip":"rs_port"\"} " vals[3]
    print "ipvs_incoming_bytes_total{vip=\""vip_port"\",backend=\""rs_ip":"rs_port"\"} " vals[4]
    print "ipvs_outgoing_bytes_total{vip=\""vip_port"\",backend=\""rs_ip":"rs_port"\"} " vals[5]
}' > "$TEMP"

mv "$TEMP" "$OUTPUT"

Best Practices Summary

Conclusion

IPVS provides a high-performance, kernel-level load balancing foundation, but its raw speed must be paired with deliberate security engineering. The hardening measures outlined in this tutorial—ARP suppression, firewall shielding, connection tracking protection, VRRP authentication, kernel parameter tuning, and continuous monitoring—transform a functional IPVS setup into a resilient, production-grade deployment. Each layer of hardening addresses a specific risk vector, and together they form a defense-in-depth posture that protects both the load balancing infrastructure and the backend services it fronts. Apply these practices incrementally, test each change in a staging environment, and maintain audit trails to ensure your IPVS deployment remains secure as your infrastructure evolves.

🚀 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