Linux File Descriptors & nofile ulimit Tuning: Stop 'Too many open files' in Pakistan

Fix fatal 'Too many open files' and 500 Internal Server Error crashes in Nginx, MariaDB, and Redis by tuning Linux fs.file-max, ulimit nofile, and systemd service limits.

Linux File Descriptors & nofile ulimit Tuning: Stop 'Too many open files' in Pakistan

Under the classic Unix philosophy, “everything is a file”.

In Linux, a file descriptor (FD) is not just a pointer to a physical document on an SSD. A file descriptor represents an open configuration file, a temporary scratch buffer, an active database .ibd tablespace, a UNIX domain socket between Nginx and PHP-FPM, and—most importantly—every single incoming TCP connection from a website visitor.

When your website experiences a surge during a marketing flash sale in Pakistan, Nginx opens thousands of simultaneous client TCP connections while opening thousands of upstream connections to PHP-FPM and MariaDB.

If your operating system operates under default resource limits, your server abruptly collapses with the fatal error:

nginx: [alert] 18452#0: *48120 socket() failed (24: Too many open files)

Or in MariaDB’s error.log:

[ERROR] Error in accept: Too many open files

To visitors, your site serves generic 500 Internal Server Error or drops connections completely.

In this deep systems engineering tutorial, we examine the three distinct layers of Linux file descriptor governance, show you how to inspect per-process limits, and explain how to calibrate nofile thresholds across sysctl, limits.conf, and systemd.


Key Takeaways for DevOps & System Administrators

  • The 1,024 File Descriptor Default Trap: By default, Linux user sessions inherit a soft nofile limit of just 1,024 file descriptors. On a web server handling 500 concurrent connections, each connection using 2 sockets plus static files immediately breaches 1,024, crashing the process.
  • The Three Governance Layers: File descriptor ceilings are enforced at three distinct layers: 1) System-wide kernel ceiling (fs.file-max), 2) PAM user session limits (/etc/security/limits.conf), and 3) Modern systemd service unit overrides (LimitNOFILE). Tuning only one layer while ignoring the others leaves the limit restricted.
  • Modern Systemd Precedence: In Ubuntu 20.04+, Debian 11+, and RHEL/AlmaLinux 8/9, services started via systemctl ignore /etc/security/limits.conf entirely! You must configure LimitNOFILE directly inside the service override file.
  • Enterprise Scale Architecture: Extreme concurrency workloads processing over 50,000 requests per second run best on bare-metal Dedicated Servers in Pakistan with dedicated memory bandwidth, zero virtualization limits, and sub-10ms domestic ping.

Step 1: Layer 1 – System-Wide Kernel Ceiling (fs.file-max)

The first layer governs the absolute maximum number of open file handles the entire operating system kernel is permitted to allocate across all running processes combined.

Check your current system ceiling:

sysctl fs.file-max

On typical modern distributions, this value is set to a reasonable number (e.g., 1 to 2 million). However, on smaller cloud VPS instances, it may be restricted to 65,536.

To raise the system-wide ceiling to 2,097,152 (2 Million):

sudo sysctl -w fs.file-max=2097152

Add this to /etc/sysctl.d/99-file-max.conf to persist across reboots:

# Maximum open files system-wide
fs.file-max = 2097152

Step 2: Layer 2 – User Session Limits (/etc/security/limits.conf)

This layer governs shells, scripts, and processes launched directly by specific users (e.g., root, nginx, mysql, www-data).

Edit /etc/security/limits.conf:

sudo nano /etc/security/limits.conf

Add the following lines at the bottom of the file:

*               soft    nofile          1048576
*               hard    nofile          1048576
root            soft    nofile          1048576
root            hard    nofile          1048576
nginx           soft    nofile          1048576
nginx           hard    nofile          1048576
mysql           soft    nofile          1048576
mysql           hard    nofile          1048576

(Note: soft is the current effective limit; hard is the maximum ceiling a non-root process can increase its soft limit to).


Step 3: Layer 3 – Systemd Service Unit Overrides (Mandatory for Daemons)

Because modern Linux services (Nginx, MariaDB, PHP-FPM, Redis) are managed by systemd, they bypass PAM session limits and use systemd default units (which often revert to 1,024 or 4,096)!

You must configure systemd drop-in overrides for each critical daemon.

1. Nginx Service Override:

sudo systemctl edit nginx

Paste the following directives:

[Service]
LimitNOFILE=1048576

In your main /etc/nginx/nginx.conf, also ensure worker connections can leverage these descriptors:

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

# Match worker_rlimit_nofile to the systemd limit
worker_rlimit_nofile 1048576;

2. MariaDB / MySQL Service Override:

sudo systemctl edit mariadb

Paste:

[Service]
LimitNOFILE=1048576

In /etc/my.cnf under [mysqld]:

[mysqld]
open_files_limit = 1048576
table_open_cache = 4096
table_definition_cache = 2048

Reload systemd daemon and restart services:

sudo systemctl daemon-reload
sudo systemctl restart nginx
sudo systemctl restart mariadb

Step 4: Verifying Active Runtime Limits on Running Processes

Never assume your settings took effect without verifying the running process’s internal kernel table.

Find the Process ID (PID) of your Nginx master process and MariaDB:

# Check Nginx master PID
ps aux | grep "nginx: master" | grep -v grep

# Query effective limits from the /proc filesystem (e.g. PID 18450)
cat /proc/18450/limits | grep "Max open files"

Expected output:

Limit                     Soft Limit           Hard Limit           Units     
Max open files            1048576              1048576              files     

If both Soft Limit and Hard Limit display 1048576, your web server can now smoothly handle hundreds of thousands of concurrent client sockets, keepalives, and static assets without ever dropping a connection!


Scaling Enterprise Workloads on Dedicated Bare Metal

Tuning file descriptors allows Linux to keep millions of sockets open simultaneously. However, servicing those sockets requires unshared physical memory bandwidth and massive CPU interrupt handling capacity.

When running on virtualized VPS instances, CPU core contention can throttle network interrupt handling (softirqs), causing packet latency even if file descriptors remain available.

Upgrading to high-throughput Dedicated Servers provides unshared multi-core AMD EPYC or Intel Xeon processors capable of servicing heavy I/O workloads with zero throttling.

For Pakistani webmasters, fintech apps, and e-commerce platforms, our Dedicated Servers in Pakistan provide domestic sub-10ms network routes across PTCL, Nayatel, and StormFiber with enterprise hardware firewall protection.

Ready for True Bare-Metal & Enterprise Cloud Power in Pakistan?

Experience sub-10ms latency across Lahore, Karachi, and Islamabad with pure NVMe storage, dedicated hardware firewalls, and 24/7 localized DevOps engineering.