Troubleshooting ‘Nginx workers connection limit reached’ on CentOS Stream / Rocky Linux

Written by

in

Resolve Nginx connection limit errors on CentOS Stream & Rocky Linux. Learn to tune worker_connections, file descriptors, and kernel parameters for high traffic.

When your Nginx web server experiences heavy traffic or misconfiguration, you might encounter issues where new connections are dropped, requests time out, or users see "502 Bad Gateway" or "503 Service Unavailable" errors. A common underlying cause on high-load systems is hitting the Nginx worker connection limit, leading to performance degradation or complete service interruption. This guide will walk you through diagnosing and resolving this critical issue on CentOS Stream and Rocky Linux environments.

Symptom & Error Signature

Users will typically experience slow page loads, connection refused errors, or HTTP 502/503 status codes. In the Nginx error logs, usually found at /var/log/nginx/error.log, you will observe messages similar to these:

2023/10/26 14:35:01 [alert] 1234#1234: *1234567 too many open files: 1024, max_connections: 1024 (client: 192.168.1.1, server: example.com, request: "GET / HTTP/1.1", host: "example.com")
2023/10/26 14:35:02 [alert] 1234#1234: *1234568 worker_connections are not enough while connecting to upstream (X.X.X.X:80)
2023/10/26 14:35:03 [crit] 1235#1235: *1234569 accept() failed (24: Too many open files)

These error messages clearly indicate that Nginx workers are unable to establish new connections, either due to their own configured limits or system-wide file descriptor constraints.

Root Cause Analysis

The "Nginx workers connection limit reached" error typically stems from one or more of the following underlying issues:

  1. Insufficient workerconnections: This is the most direct cause. The workerconnections directive in nginx.conf defines the maximum number of simultaneous connections that a single Nginx worker process can handle. If the aggregate capacity (workerprocesses * workerconnections) is lower than the actual peak concurrent connections, Nginx will drop new requests.
  2. Too Few workerprocesses: While workerconnections limits individual workers, workerprocesses determines how many workers Nginx spawns. If this value is too low, the server might not fully utilize available CPU cores, bottlenecking processing capacity even if workerconnections is high per worker.
  3. System-wide File Descriptor Limits (ulimit -n): Nginx is a file descriptor (FD)-intensive application. Each client connection, as well as connections to upstream servers, uses at least one file descriptor. If the operating system's per-process file descriptor limit (ulimit -n) for the Nginx process is lower than its configured worker_connections, Nginx will fail with "Too many open files" errors before reaching its internal connection limit.
  4. Kernel TCP Backlog Limits (net.core.somaxconn, net.ipv4.tcpmaxsyn_backlog): These kernel parameters control the maximum length of the queue for pending TCP connections. If Nginx processes established connections slower than new connections arrive, these queues can overflow, leading to dropped connections even before Nginx can accept them, often presenting as connection resets on the client side.
  5. Upstream Server Bottlenecks: If Nginx is configured as a reverse proxy, a slow or overloaded upstream application server (e.g., PHP-FPM, Node.js app, Tomcat) can cause Nginx worker processes to wait for responses, holding open connections and thereby exhausting the worker_connections pool prematurely.

Step-by-Step Resolution

Follow these steps to diagnose and resolve the Nginx worker connection limit issue.

1. Analyze Current Nginx & System Configuration

Before making changes, understand your current settings:

First, identify the Nginx master process ID: `bash sudo systemctl status nginx | grep Main PID # Example output: Main PID: 1234 (nginx) ` Replace 1234 with your Nginx master PID in subsequent commands.

  • Check Nginx workerprocesses and workerconnections:
  • `bash
  • grep -E 'workerprocesses|workerconnections' /etc/nginx/nginx.conf
  • `
  • Check Nginx process's file descriptor limit:
  • `bash
  • cat /proc/$(sudo systemctl show –property MainPID nginx | cut -d= -f2)/limits | grep 'Max open files'
  • `
  • Compare this "Max open files" (soft limit) with your workerconnections value. workerconnections must be less than or equal to this limit.
  • Check system-wide kernel TCP backlog settings:
  • `bash
  • sysctl net.core.somaxconn net.ipv4.tcpmaxsyn_backlog
  • `

2. Adjust Nginx workerconnections and workerprocesses

Modify the Nginx main configuration file, typically /etc/nginx/nginx.conf.

  1. Open the Nginx configuration file:
  2. `bash
  3. sudo vi /etc/nginx/nginx.conf
  4. `
  5. Adjust workerprocesses and workerconnections:
  6. Locate the worker_processes and events blocks.
  7. * Set worker_processes to auto to allow Nginx to detect the optimal number of processes based on CPU cores, or explicitly to the number of CPU cores available on your server.
  8. * Significantly increase worker_connections. A common starting point for high-traffic sites is 10240 or 20480. You can go higher, but remember each connection consumes some memory.
  9. * Consider adding multi_accept on; in the events block. This tells a worker process to accept as many new connections as possible at once, rather than one by one, which can be beneficial under very high load.

user nginx; worker_processes auto; # Set to 'auto' or the number of CPU cores (e.g., 4, 8)

error_log /var/log/nginx/error.log warn; pid /run/nginx.pid;

events { worker_connections 20480; # Increase this value significantly (e.g., 10240, 20480, 40960) multi_accept on; # Optional: Enable multiple connection accepts per worker }

http { include /etc/nginx/mime.types; default_type application/octet-stream;

… other http directives … } ` 3. Test Nginx configuration: `bash sudo nginx -t ` Ensure you see syntax is ok and test is successful. 4. Reload Nginx service: `bash sudo systemctl reload nginx `

[!IMPORTANT] The total number of concurrent connections Nginx can theoretically handle is workerprocesses workerconnections. Ensure this value is adequate for your anticipated peak traffic but also mindful of your server's RAM and CPU resources. A common guideline is to set worker_connections to at least 2 UlimitNOFILE to account for both client and upstream connections.

3. Increase System-wide File Descriptor Limits (ulimit)

The Nginx process's file descriptor limit must be equal to or greater than its worker_connections setting. We'll modify the Systemd service unit for Nginx to achieve this.

  1. Create or edit the Nginx Systemd override file:
  2. `bash
  3. sudo systemctl edit nginx
  4. `
  5. This will open a file like /etc/systemd/system/nginx.service.d/override.conf.
  6. Add the LimitNOFILE directive:
  7. Add the following lines to the file, setting LimitNOFILE to a value higher than your worker_connections (e.g., 65536 or 131072).
    [Service]
    LimitNOFILE=65536
    ```
3.  **Save and exit.**
4.  **Reload the Systemd daemon:**
    ```bash
    sudo systemctl daemon-reload
    ```
5.  **Restart Nginx to apply changes:**
    ```bash
    sudo systemctl restart nginx
    ```
6.  **Verify the new `ulimit` for the Nginx process:**
    ```bash
    cat /proc/$(sudo systemctl show --property MainPID nginx | cut -d= -f2)/limits | grep 'Max open files'
    ```

[!WARNING] While increasing LimitNOFILE allows Nginx to handle more connections, setting it excessively high without sufficient RAM can lead to memory exhaustion and system instability. Start with 65536 or 131072 and monitor your server's performance.

4. Tune Kernel TCP Backlog Parameters

Adjusting kernel parameters can help the system handle bursts of new connections more gracefully.

  1. Create or edit a custom sysctl configuration file:
  2. `bash
  3. sudo vi /etc/sysctl.d/90-custom.conf
  4. `
  5. (You can also use /etc/sysctl.conf, but .d files are cleaner for custom settings).
  6. Add or modify the following parameters:
    # Maximum number of connections that can be queued for a listening socket

Maximum number of SYN requests that the kernel will keep in memory net.ipv4.tcpmaxsyn_backlog = 8192

Allow reusing sockets in TIME_WAIT state for new connections (can help with port exhaustion) net.ipv4.tcptwreuse = 1

Reduce TIME_WAIT state duration (for faster socket cleanup) net.ipv4.tcpfintimeout = 30 ` 3. Save and exit. 4. Apply the sysctl changes: `bash sudo sysctl -p /etc/sysctl.d/90-custom.conf ` (Or sudo sysctl -p if you edited /etc/sysctl.conf). 5. Verify the new kernel parameters: `bash sysctl net.core.somaxconn net.ipv4.tcpmaxsynbacklog net.ipv4.tcptwreuse net.ipv4.tcpfin_timeout `

[!NOTE] net.core.somaxconn affects the listen directive's backlog parameter in Nginx. net.ipv4.tcpmaxsyn_backlog is crucial for preventing SYN flood attacks and managing a high rate of new connection attempts. These values should be adjusted incrementally based on your specific traffic patterns and monitoring.

5. Monitor and Optimize

After implementing these changes, continuous monitoring is crucial to ensure stability and optimal performance.

  • Monitor Nginx error logs: Keep an eye on /var/log/nginx/error.log for any new connection-related errors.
  • System resource monitoring: Use tools like atop, htop, dstat, or grafana/prometheus to monitor CPU, memory, and network usage.
  • Network statistics:
  • * Check for connections in various states: netstat -nat | awk '{print $NF}' | sort | uniq -c | sort -nr
  • * Summarize network statistics: ss -s
  • Nginx Stub Status Module: If enabled, monitor Nginx's active connections and requests per second:
  • `bash
  • curl -s http://localhost/nginx_status
  • `
  • (Requires stubstatus to be enabled in your Nginx configuration, e.g., in a server block: location /nginxstatus { stub_status on; allow 127.0.0.1; deny all; }).
  • Further Nginx Optimization:
  • * Consider keepalivetimeout and keepaliverequests if your application benefits from persistent connections.
  • * Optimize proxy buffering settings (proxybuffering, proxybuffers, proxybuffersize) if Nginx is a reverse proxy.
  • * Ensure your upstream application servers (e.g., PHP-FPM, uWSGI, Node.js) are also adequately scaled and configured to handle the increased load Nginx is now passing to them.

By systematically adjusting Nginx configuration and underlying OS limits, you can significantly improve your server's ability to handle high concurrent connections, ensuring a more stable and responsive web service.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *