Loading learning content...
Before cookies dominated the web, before sophisticated HTTP parsing became commonplace, there was a simpler approach to session persistence: use the client's IP address as the identifier.
The logic seems elegant: every TCP connection has a source IP address. If we consistently route all requests from the same IP to the same backend server, we achieve session affinity without any application-layer involvement. No cookies to manage, no HTTP headers to parse, no client cooperation required.
This simplicity made IP-based persistence the go-to solution for early load balancers and Layer 4 routing. It remains widely available today (often called 'source IP affinity,' 'IP hash,' or 'client IP persistence').
But here's the uncomfortable truth: IP-based persistence is fundamentally broken in the modern internet.
Not 'sometimes problematic.' Not 'edge-case limited.' Fundamentally broken for most real-world scenarios. This page explains why—while also identifying the narrow situations where IP-based persistence still makes sense.
By the end of this page, you will understand the mechanics of IP-based persistence, why it fails in modern network environments (NAT, CGN, mobile networks, proxies), when it remains appropriate, and how to configure it across major load balancers. Most importantly, you'll know when NOT to use it.
IP-based persistence operates at the network layer, making routing decisions based on the source IP address of incoming connections. Here's the fundamental algorithm:
Basic Hash Algorithm:
server_index = hash(source_ip_address) % number_of_servers
The load balancer:
Two Implementation Approaches:
ip_hash in NGINXConsistent Hashing Variant:
Modern implementations often use consistent hashing to minimize disruption when servers are added or removed:
With 10 servers, removing one server with traditional hashing shuffles approximately 90% of clients. With consistent hashing, it's approximately 10%—a dramatic improvement for operational stability.
IP-based persistence works at Layer 4 (transport layer), meaning it can persist any TCP or UDP traffic—not just HTTP. This makes it valuable for non-HTTP protocols like database connections, SMTP, or custom TCP services where cookie-based persistence isn't possible.
The fundamental assumption of IP-based persistence is that each user has a unique, stable IP address. This assumption is catastrophically wrong in the modern internet.
Network Address Translation (NAT):
NAT allows multiple devices to share a single public IP address. Originally a workaround for IPv4 address exhaustion, NAT is now ubiquitous:
The Scale of the Problem:
| Environment | Typical Users per IP | Impact on IP Persistence |
|---|---|---|
| Residential (Home NAT) | 5-15 devices | Family members can't use site simultaneously |
| Small Office | 20-100 employees | All staff routed to single server |
| Corporate Enterprise | 1,000-10,000 employees | Massive load imbalance |
| University Campus | 10,000-50,000 students | Complete persistence failure |
| ISP CGN (Carrier-Grade NAT) | 1,000-100,000 subscribers | Catastrophic load concentration |
| Mobile Carrier | Varies wildly | IPs change mid-session |
Carrier-Grade NAT (CGN):
IPv4 exhaustion has driven ISPs to deploy Carrier-Grade NAT (CGN), also called Large Scale NAT (LSN). Under CGN:
Major ISPs worldwide deploy CGN. In some developing regions, CGN is universal. Your assumption of 'one IP = one user' might be off by a factor of 10,000.
Visualization of the Problem:
Production incidents caused by IP persistence + NAT are common. A single corporate client sends 10,000 users; one server handles all of them while others sit idle. Auto-scaling can't help—the traffic distribution is fundamentally broken. Server 1 crashes from load while Server 2-10 run at 5% utilization.
NAT causes load imbalance, but mobile networks create a different problem: IP addresses that change mid-session.
Why Mobile IPs Change:
The Session Destruction Pattern:
The Scale of Mobile Traffic:
As of 2024, mobile devices account for approximately 60% of global web traffic. In many regions, mobile-first users dominate. An architecture that breaks for mobile users is broken for the majority of your users.
WiFi Offload Complexity:
Modern smartphones aggressively offload traffic to WiFi when available:
That's potentially four different IP addresses in a single morning, each potentially routing to a different server. Any session state stored on Server 1 is lost when the user hits Server 2.
Mobile users don't understand (or care) that their IP changed. They just know your app 'lost their stuff.' These invisible failures destroy user trust. In a world of app store ratings and social media complaints, invisible infrastructure failures become very visible business problems.
Beyond NAT and mobile networks, various proxy technologies further complicate IP-based persistence:
Forward Proxies:
Organizations route traffic through forward proxies for security, filtering, or caching:
Reverse Proxies and CDNs:
If you're behind a CDN (Cloudflare, Akamai, CloudFront), the 'source IP' your origin load balancer sees is the CDN edge server—not the actual client:
Client (IP: 203.0.113.50) → CDN Edge (IP: 198.51.100.1) → Your Load Balancer
Your load balancer sees 198.51.100.1 for millions of different users. All CDN traffic from that edge server gets routed to the same backend.
VPN Services:
VPN usage has exploded for privacy, remote work, and geo-circumvention:
| Proxy Type | How It Affects Source IP | Impact on IP Persistence |
|---|---|---|
| Corporate Forward Proxy | Thousands of employees → few IPs | Severe load imbalance |
| CDN Edge (Cloudflare, etc.) | Millions of users → hundreds of edge IPs | Near-complete persistence failure |
| Consumer VPN (NordVPN, etc.) | Thousands of subscribers → shared exit IPs | Random session loss, load imbalance |
| Tor Network | Millions of users → few exit nodes | Complete persistence failure |
| Corporate VPN (Split Tunnel) | Remote workers → corporate IP | Partial, unpredictable issues |
| ISP Transparent Proxy | Subscribers → proxy IP | Invisible but significant |
The X-Forwarded-For 'Solution' (and Why It's Not):
Some suggest using X-Forwarded-For header instead of TCP source IP. This header (when properly set by proxies) contains the original client IP:
X-Forwarded-For: client_ip, proxy1_ip, proxy2_ip
Problems with X-Forwarded-For:
X-Forwarded-For is valuable for logging, rate limiting (at the right layer), and geographic routing. But it doesn't fundamentally solve IP persistence problems—it just moves them from 'CDN IP' to 'client IP,' which is still usually behind NAT.
After all these warnings, are there scenarios where IP-based persistence works? Yes—narrow but legitimate use cases exist:
Scenario 1: Internal Services / Service-to-Service Communication
Within a datacenter or cloud VPC, service-to-service calls have stable, unique IPs:
Scenario 2: Known, Controlled Client Population
When you control clients and know their network topology:
Scenario 3: Non-HTTP Protocols
For protocols without cookie/header support, IP persistence may be the only option:
Scenario 4: Short-Duration Affinity
When persistence only needs to last seconds, not sessions:
If you answered 'yes' to most of these, IP persistence might work.
But if even one involves public internet users, mobile clients, or web browsers—reconsider. The edge cases will bite you eventually.
Some architectures use IP persistence as a fallback. Attempt cookie-based persistence first; if no cookie, fall back to IP hash. This provides graceful degradation while optimizing for the common case. HAProxy and others support this pattern.
Despite its limitations, you may need to configure IP persistence for specific scenarios. Here's how across major platforms:
123456789101112131415161718192021222324252627282930313233343536373839404142
# Basic IP hashupstream backend { ip_hash; # Enable IP-based persistence server 10.0.0.1:8080; server 10.0.0.2:8080; server 10.0.0.3:8080;} # With weight and backupupstream backend_weighted { ip_hash; server 10.0.0.1:8080 weight=3; server 10.0.0.2:8080 weight=2; server 10.0.0.3:8080 backup; # Only used when others fail} # Using consistent hash on specific variableupstream backend_hash { hash $remote_addr consistent; # Consistent hashing server 10.0.0.1:8080; server 10.0.0.2:8080; server 10.0.0.3:8080;} # Hash on X-Forwarded-For (use with trusted proxies only)upstream backend_xff { hash $http_x_forwarded_for consistent; server 10.0.0.1:8080; server 10.0.0.2:8080;} server { listen 80; location / { proxy_pass http://backend; }}NGINX Notes:
ip_hash uses first three octets of IPv4 (class C network)hash $var consistent is more flexible and uses consistent hashingIf you're using IP-based persistence, monitoring is critical to detect the inevitable problems:
Key Metrics to Watch:
Troubleshooting Common Issues:
Issue 1: Severe Load Imbalance
Symptoms: One server at 90% CPU, others at 10%.
Diagnosis:
Mitigation:
Issue 2: Sessions Breaking for Specific Users
Symptoms: Certain users report constant session loss, others unaffected.
Diagnosis:
Mitigation:
Issue 3: All Traffic Going to One Server After Deployment
Symptoms: After adding/removing servers, traffic distribution radically changes.
Diagnosis:
Mitigation:
hash-type consistent in HAProxy)Set up alerts for load imbalance ratios. If any server receives more than 2x the average requests, trigger investigation. This catches NAT concentration problems before they become outages.
We've thoroughly examined IP-based persistence—its mechanics, failures, and limited appropriate uses. Let's synthesize:
| Aspect | IP-Based Persistence | Cookie-Based Persistence |
|---|---|---|
| Works with NAT | ❌ Fails badly | ✅ Works perfectly |
| Works with Mobile | ❌ Breaks on IP change | ✅ Works across networks |
| Works with CDN/Proxy | ❌ All clients = one IP | ✅ Each client distinct |
| Non-HTTP Protocols | ✅ Works (Layer 4) | ❌ HTTP only (Layer 7) |
| Client Cooperation | ✅ None required | ⚠️ Needs cookie support |
| Load Balancer State | ⚠️ Depends on impl. | ✅ Minimal (cookie stored on client) |
| Security Exposure | ✅ Minimal | ⚠️ Needs careful cookie config |
| Server Pool Changes | ⚠️ Disrupts sessions | ⚠️ Disrupts sessions (similar) |
What's Next:
We've now covered both major persistence mechanisms—cookies and IP-based. But sticky sessions, regardless of implementation, have fundamental drawbacks. Next, we'll examine the drawbacks of sticky sessions as an architectural pattern—load imbalance, failover complexity, and scalability constraints—setting up the case for stateless alternatives.
You now understand IP-based persistence comprehensively: how it works, why it fails in modern networks, the narrow scenarios where it's appropriate, and how to configure it when needed. More importantly, you know when NOT to use it—which is most of the time for public-facing services.