Platform Engineering
6 min readMay 27, 2026Updated August 19, 2026

Fix Nginx 'Too Many Open Files' Error

AJ
Ajeet Yadav
Platform & Cloud Engineer
Fix Nginx 'Too Many Open Files' Error

Quick answer

Nginx's 'too many open files' error (errno 24) means a worker process hit its file descriptor limit. The fix requires changes at three levels — nginx.conf, the systemd unit, and the OS — all three are needed.

6 min read · Platform Engineering

Fix Nginx 'Too Many Open Files' Error

In /var/log/nginx/error.log:

2026/06/01 10:00:00 [crit] 12345#12345: *5000 open() "/var/www/html/index.html" failed (24: Too many open files), client: 203.0.113.1, server: example.com

Or when Nginx itself can't open its log:

nginx: [emerg] open() "/var/log/nginx/error.log" failed (24: Too many open files)

Error 24 = EMFILE — the Nginx worker process has hit its open file descriptor limit.


Why This Happens

Every open resource counts as a file descriptor in Linux:

  • Each active client connection: 1 fd (client socket)
  • Each upstream connection: 1 fd (upstream socket)
  • Each static file being served: 1 fd
  • Log files: 1 fd per log file per worker

Under traffic spikes, a single Nginx worker can need thousands of file descriptors simultaneously. The default OS limit is often 1024 — far too low for a production server.


Diagnose First

bash
1# Current hard limit for the shell
2ulimit -Hn
3
4# Actual limit of the running Nginx master process
5cat /proc/$(cat /run/nginx.pid)/limits | grep "Max open files"
6# Max open files   1024   1024   files   ← too low
7
8# Current fd usage by Nginx workers
9ls /proc/$(cat /run/nginx.pid)/fd | wc -l
10
11# Check how many worker processes are running
12ps aux | grep "nginx: worker"

The Fix — Three Layers Required

The OS, systemd, and Nginx each enforce their own limits. Setting only one is not enough.

Layer 1: Nginx config — worker_rlimit_nofile

In /etc/nginx/nginx.conf, at the top level (before the events block):

nginx
1worker_processes auto;         # Set to number of CPU cores
2worker_rlimit_nofile 65535;   # Max open file descriptors per worker process
3
4events {
5    worker_connections 4096;   # Max simultaneous connections per worker
6    use epoll;                 # Linux: use epoll I/O event model
7    multi_accept on;           # Accept multiple connections per event loop tick
8}

Rule of thumb: worker_rlimit_nofileworker_connections × 2 (each proxied connection needs at least a client socket and an upstream socket).

Layer 2: systemd service limit

Nginx on systemd ignores ulimit settings from the shell. It has its own LimitNOFILE in the service unit, which overrides the OS default.

Create an override:

bash
systemctl edit nginx

Add:

ini
[Service]
LimitNOFILE=65535

Save, then apply:

bash
systemctl daemon-reload
systemctl restart nginx

Verify the systemd limit took effect:

bash
cat /proc/$(cat /run/nginx.pid)/limits | grep "Max open files"
# Max open files   65535   65535   files   ← correct

Layer 3: OS limits

For non-systemd contexts (login shells, init scripts), set in /etc/security/limits.conf:

www-data   soft   nofile   65535
www-data   hard   nofile   65535

Replace www-data with the user Nginx runs as (check with ps aux | grep nginx | grep worker).

Also raise the system-wide kernel fd maximum:

bash
echo "fs.file-max = 2097152" >> /etc/sysctl.d/99-nginx.conf
sysctl -p /etc/sysctl.d/99-nginx.conf

Stuck on this in production?

We debug exactly this kind of issue for platform teams — usually in a single working session.

Talk to us

Verify the Fix

bash
1# Confirm Nginx limit after restart
2cat /proc/$(cat /run/nginx.pid)/limits | grep "Max open files"
3
4# Monitor fd usage under load
5watch -n 2 'ls /proc/$(cat /run/nginx.pid)/fd | wc -l'
6
7# Confirm no more errno 24 in error log
8tail -f /var/log/nginx/error.log | grep "Too many open files"

If fd usage under load stays well below 65535 and the error stops appearing, the fix worked.


Complete Tuned /etc/nginx/nginx.conf

nginx
1user www-data;
2worker_processes auto;
3worker_rlimit_nofile 65535;    # ← Layer 1 fix
4pid /run/nginx.pid;
5
6events {
7    worker_connections 4096;
8    use epoll;
9    multi_accept on;
10}
11
12http {
13    sendfile on;
14    tcp_nopush on;
15    tcp_nodelay on;
16    keepalive_timeout 65;
17    types_hash_max_size 2048;
18    server_tokens off;          # Don't expose Nginx version in headers
19
20    include /etc/nginx/mime.types;
21    default_type application/octet-stream;
22
23    access_log /var/log/nginx/access.log;
24    error_log  /var/log/nginx/error.log warn;
25
26    gzip on;
27    gzip_types text/plain text/css application/json application/javascript;
28
29    include /etc/nginx/sites-enabled/*;
30}
bash
nginx -t && systemctl reload nginx

Quick Reference

LocationSettingValue
/etc/nginx/nginx.confworker_rlimit_nofile65535
systemctl edit nginxLimitNOFILE65535
/etc/security/limits.confwww-data hard nofile65535
/etc/sysctl.d/99-nginx.conffs.file-max2097152

All four must be set. Missing any one of them means the lowest limit wins.


See Also

Frequently Asked Questions

Why do I need to change limits in three places?

Because they nest. The kernel-wide maximum bounds everything, the per-process limit bounds the worker, and NGINX's own directive bounds connections per worker. Raising one and not the others means the lowest ceiling still applies, which is why a change that looks correct has no effect.

Why did my systemd service ignore the limits I set?

Because systemd does not read the shell limits file for services it starts — it applies its own. Set the limit in the unit or a drop-in override, then reload the daemon and restart the service. This is the most common reason the fix appears not to work.

How do I know what the limit should be?

worker_rlimit_nofile is per worker, so derive it from connections per worker with headroom — a proxied request consumes a descriptor on both the client and upstream side, so roughly twice worker_connections plus open files. The system-wide ceiling is what must account for every worker. Verify against the running process rather than trusting the configuration.

Could this be a leak rather than a limit?

Possibly. If descriptor count climbs steadily under stable traffic, something is not closing connections — often an upstream with keepalive misconfigured. Raising the ceiling buys time; watch whether the count plateaus after the change or simply takes longer to hit the new limit.

Official References

Was this article helpful?

Be the first to rate this article

Related Topics

Nginx
Troubleshooting
Linux
File Descriptors
Performance
DevOps

Found this useful? Share it.

Practice this

Related tools

Read Next