Solving “Too many open files” Error in Nginx: Comprehensive Guide to Increasing File Descriptor Limits


1 views

When running Nginx on Ubuntu, you might encounter the dreaded "accept4() failed (24: Too many open files)" error in your error logs. This occurs when Nginx workers exhaust their file descriptor limits, preventing new connections from being accepted.

Before making changes, let's examine the current system status:

# Check current file-max value
cat /proc/sys/fs/file-max

# Check Nginx process limits (replace PID with actual process ID)
cat /proc/<PID>/limits | grep "Max open files"

# Verify running Nginx processes
ps aux | grep nginx

Here's how to properly increase file descriptor limits for Nginx:

1. Edit system-wide limits in /etc/security/limits.conf:

# Add these lines at the end of the file
* soft nofile 65536
* hard nofile 65536
root soft nofile 65536
root hard nofile 65536
www-data soft nofile 65536
www-data hard nofile 65536
nobody soft nofile 65536
nobody hard nofile 65536

2. Ensure PAM reads these limits by editing /etc/pam.d/common-session:

session required pam_limits.so

Add these directives to your Nginx configuration (typically in nginx.conf):

worker_rlimit_nofile 65536;

events {
    worker_connections 20480;
    use epoll;
    multi_accept on;
}

Increase system-wide limits by editing /etc/sysctl.conf:

fs.file-max = 500000
fs.nr_open = 500000
net.ipv4.tcp_max_syn_backlog = 10240
net.core.somaxconn = 2048
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1

Apply changes immediately with:

sysctl -p

After implementing all changes, verify the new limits:

# Check system-wide limit
cat /proc/sys/fs/file-max

# Check process limits
cat /proc/$(pgrep -f "nginx: worker" | head -1)/limits | grep "Max open files"

# Count current open files per Nginx worker
ls -1 /proc/$(pgrep -f "nginx: worker" | head -1)/fd | wc -l

If limits still aren't applying correctly:

  • Ensure you've restarted both the system and Nginx
  • Check if AppArmor/SELinux is enforcing limits
  • Verify Nginx isn't being started with custom ulimits
  • Consider using systemd override files if applicable
# For systemd systems
systemctl edit nginx.service

# Add these lines:
[Service]
LimitNOFILE=65536

When Nginx workers cannot accept new connections due to file descriptor limits, you'll see error messages like:

2013/06/18 21:35:03 [crit] 3427#0: accept4() failed (24: Too many open files)

This indicates your system has hit the maximum allowed open files limit for the Nginx processes. The key is to configure this at multiple levels: system-wide, per-user, and for the Nginx service itself.

First check your current system-wide limit:

cat /proc/sys/fs/file-max

To permanently increase it, edit /etc/sysctl.conf:

fs.file-max = 500000

Apply changes immediately:

sysctl -p

For Ubuntu systems using systemd (later versions), the traditional /etc/security/limits.conf approach might not work. Instead, create a custom systemd override:

mkdir -p /etc/systemd/system/nginx.service.d
echo "[Service]
LimitNOFILE=65536" > /etc/systemd/system/nginx.service.d/limits.conf
systemctl daemon-reload
systemctl restart nginx

In your Nginx configuration (nginx.conf), add these directives in the main context:

worker_rlimit_nofile 65536;
events {
    worker_connections 40000;
}

After making changes, verify they took effect:

# Check system-wide limit
cat /proc/sys/fs/file-max

# Check process limits
cat /proc/$(pgrep -f "nginx: worker" | head -1)/limits | grep "Max open files"

# Check current usage
lsof -p $(pgrep -f "nginx: worker" | head -1) | wc -l

If limits still don't apply:

  1. Ensure no duplicate configurations exist
  2. Check for apparmor/selinux restrictions
  3. Verify the correct user (www-data/nobody) is being limited
  4. Check kernel logs (dmesg) for related errors

When increasing file descriptors:

  • Monitor memory usage (each FD consumes resources)
  • Adjust worker_connections based on your expected traffic
  • Consider using epoll for better performance with many connections
events {
    use epoll;
    worker_connections 40000;
    multi_accept on;
}