The Problem: Hitting the File Descriptor CeilingBusy Nginx servers often hit a wall where they suddenly stop accepting traffic or fail to communicate with backend services like Node.js or PHP-FPM. If you check your logs at /var/log/nginx/error.log and see a (24: Too many open files) critical error, your server has run out of resources. This usually happens because Linux treats almost everything—from network sockets to log files—as a File Descriptor (FD).
By default, many Linux distributions cap a single process at 1,024 open files. While this is safe for a desktop, a high-performance web server handling 5,000 concurrent users will crash into this limit in milliseconds. To fix this, we need to raise the ceiling across the OS, the service manager, and Nginx itself.
Step 1: Check Your Current LimitsStart by identifying the actual limit applied to your running Nginx worker processes. You can find the Process ID (PID) and inspect its limits directly via the /proc filesystem.
# Identify the PID of an active Nginx worker
ps aux | grep nginx
# Check the limits for that PID (e.g., 1234)
cat /proc/1234/limits | grep "Max open files"
If you see a "Soft Limit" of 1024, you've found your bottleneck. This number is far too low for modern production workloads.
Step 2: Adjust OS-Level LimitsThe operating system needs permission to hand out more descriptors to the Nginx user. Open the /etc/security/limits.conf file to define these global boundaries.
sudo nano /etc/security/limits.conf
Add these lines at the bottom. Make sure to use the user your Nginx service runs as (typically www-data or nginx):
nginx soft nofile 65535
nginx hard nofile 65535
This sets the limit to 65,535, a standard value for high-performance systems. However, on modern systems, this file alone isn't enough.
Step 3: Update Systemd ConfigurationModern Linux versions (Ubuntu 18.04+, CentOS 7+) use Systemd, which often ignores limits.conf for background services. You must explicitly tell Systemd to allow higher limits for the Nginx unit.
Create an override file to keep your changes safe during package updates:
sudo mkdir -p /etc/systemd/system/nginx.service.d/
sudo nano /etc/systemd/system/nginx.service.d/override.conf
Paste the following configuration:
[Service]
LimitNOFILE=65535
After saving, reload the Systemd daemon so it recognizes the new instructions:
sudo systemctl daemon-reload
Step 4: Configure Nginx Worker LimitsEven if the OS allows 65,000 files, Nginx won't use them unless you tell it to. You need to align Nginx's internal settings with your new system limits.
Open /etc/nginx/nginx.conf and add the worker_rlimit_nofile directive at the top level:
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535; # Matches the OS limit
events {
worker_connections 16384; # Keep this significantly lower than rlimit_nofile
}
http {
...
}
The 2:1 Rule: Always set worker_rlimit_nofile to at least double your worker_connections. Each proxied request uses at least two file descriptors: one for the client connection and one for the connection to your upstream backend.
Step 5: Apply and VerifyVerify your configuration for typos before restarting the service:
sudo nginx -t
If the test passes, restart Nginx to apply all changes:
sudo systemctl restart nginx
Finally, confirm the new limits are active for the new processes. Run this command to check the latest worker PID:
NEW_PID=$(pgrep -n nginx)
cat /proc/$NEW_PID/limits | grep "Max open files"
You should now see the limit reflected as 65535. Your server can now handle tens of thousands of concurrent connections without breaking a sweat.

