Troubleshooting Nginx Ephemeral Port Exhaustion on High-Concurrency Proxies

Diagnose and fix 99: Cannot assign requested address errors in Nginx reverse proxies. Tune Linux ip_local_port_range, tcp_tw_reuse, and keepalive upstream connections in Pakistan.

Troubleshooting Nginx Ephemeral Port Exhaustion on High-Concurrency Proxies

High-traffic websites, multi-tenant APIs, and microservices architectures in Pakistan frequently employ Nginx as a reverse proxy sitting in front of upstream backends (such as PHP-FPM, Node.js, Gunicorn, or Go binaries). Under sudden traffic surges—such as flash sales, breaking news announcements, or marketing campaigns—users may suddenly encounter catastrophic 502 Bad Gateway errors.

When sysadmins inspect the Nginx error log on a Dedicated Server, they encounter the following signature:

2026/10/05 01:14:22 [crit] 14201#14201: *894021 connect() to 127.0.0.1:8080 failed (99: Cannot assign requested address) while connecting to upstream, client: 202.47.32.10, server: example.pk, request: "GET /api/v1/checkout HTTP/1.1", upstream: "http://127.0.0.1:8080/api/v1/checkout"

Error 99: Cannot assign requested address does not mean the upstream service is dead. It means the operating system has completely run out of available outbound ephemeral ports to establish a new TCP socket connection to the backend service.


Understanding the TCP 4-Tuple and TIME_WAIT Accumulation

Every TCP connection is uniquely identified by a 4-tuple: [ (\text{Source IP}, \text{Source Port}, \text{Destination IP}, \text{Destination Port}) ]

When Nginx proxies an HTTP request to a local upstream daemon (e.g., 127.0.0.1:8080):

  • Destination IP: Fixed (127.0.0.1).
  • Destination Port: Fixed (8080).
  • Source IP: Fixed (127.0.0.1).
  • Source Port: Dynamically assigned from the operating system’s ephemeral port pool.

By default, standard Linux distributions allocate approximately 28,000 ephemeral ports (typically 32768 to 60999). When an HTTP request completes, the TCP protocol mandates that the closed connection enter the TIME_WAIT state for (2 \times \text{MSL}) (Maximum Segment Lifetime, default 60 seconds) to ensure delayed packets from old connections are not misinterpreted.

If your web server processes 1,000 requests per second and closes connections without reusing them, after 30 seconds you accumulate 30,000 sockets in TIME_WAIT. The ephemeral pool is exhausted, and the kernel refuses new outgoing connections, throwing 99: Cannot assign requested address.


Step-by-Step Diagnostics

Step 1: Count Active Sockets by TCP State

Execute the following command on your server or Cloud VPS:

ss -s

Example Output Under Exhaustion:

Total: 34102
TCP:   32150 (estab 1420, closed 30420, orphaned 0, timewait 30410)

If timewait exceeds 25,000, your server is choking on ephemeral port allocation.

Step 2: Check Active Ephemeral Port Range

Check the configured boundaries:

cat /proc/sys/net/ipv4/ip_local_port_range
# Default Output: 32768 60999  (Only 28,231 usable ports!)

The Three-Tier Architectural Solution

Fixing ephemeral port exhaustion requires addressing both the kernel networking limits and the upstream connection handling inside Nginx.

Tier 1: Expand Kernel Port Range & Enable tcp_tw_reuse

Edit /etc/sysctl.conf to expand the port pool and allow safe socket recycling:

# Expand ephemeral port range to allow over 64,000 ports
net.ipv4.ip_local_port_range = 1024 65535

# Allow kernel to safely reuse TIME_WAIT sockets for outgoing connections
net.ipv4.tcp_tw_reuse = 1

# Reduce FIN timeout from 60s to 15s to prune closed sockets faster
net.ipv4.tcp_fin_timeout = 15

# Increase maximum tracking limits for connection tracking table
net.netfilter.nf_conntrack_max = 1048576

Apply the new parameters immediately:

sysctl -p

Warning: Never enable net.ipv4.tcp_tw_recycle = 1. That setting has been deprecated and removed from modern Linux kernels because it breaks connections from clients behind NAT gateways (such as mobile carrier CGNAT networks across Pakistan).

Tier 2: Configure Persistent HTTP Keepalives in Nginx Upstreams

By default, Nginx opens a new TCP connection for every single incoming client request forwarded to an upstream server, closing it immediately afterward. Configuring persistent upstream keepalive pools eliminates TCP handshakes and keeps ports open:

Edit /etc/nginx/conf.d/upstream.conf:

upstream backend_app {
    server 127.0.0.1:8080;
    
    # Maintain a pool of up to 256 idle keepalive connections per worker
    keepalive 256;
    keepalive_requests 10000;
    keepalive_timeout 60s;
}

server {
    listen 80;
    server_name example.pk;

    location / {
        proxy_pass http://backend_app;
        
        # Mandatory directives to enable HTTP/1.1 persistent connections
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Crucial Note: The directive proxy_set_header Connection "" clears the default Connection: close header, permitting Nginx to maintain stateful connection reuse.

Tier 3: Bind to Multiple Upstream IP Loopback Aliases

If your proxy handles tens of thousands of requests per second, even 64,000 ports can become saturated. You can multiply the effective 4-tuple by binding to multiple local loopback addresses:

# Add loopback IP aliases
ip addr add 127.0.0.2/8 dev lo
ip addr add 127.0.0.3/8 dev lo

Update your Nginx upstream block:

upstream backend_app {
    server 127.0.0.1:8080;
    server 127.0.0.2:8080;
    server 127.0.0.3:8080;
    keepalive 256;
}

This triples your available port capacity to nearly 192,000 simultaneous sockets.


Performance Impact: Before vs. After Optimization

Metric Stock Linux / Nginx Defaults Tuned Linux + Upstream Keepalive
Available Ephemeral Ports 28,231 64,511
Sockets in TIME_WAIT (at 2k req/s) 30,000+ (Saturation) < 1,200
Proxy Handshake Overhead 3-way handshake on every request Zero (Reused persistent connections)
Median TTFB to Client 85 ms (Spiking to 502 error) 14 ms (Stable)
Peak Throughput Capacity ~1,200 req/s 18,000+ req/s

For additional server optimization strategies on production infrastructure, review our technical analyses on Troubleshooting Linux NIC Packet Drops and cPanel BIND Named Response Rate Limiting.

High-Concurrency Web Infrastructure
Deploy Dedicated Bare-Metal Servers Tuned for Massive Throughput

Eliminate 502 Bad Gateway errors, socket starvation, and proxy latency with customized high-concurrency Linux web hosting on enterprise hardware in Pakistan.