Every sysadmin knows about how to set values in /etc/security/limits.conf on Red Hat Enterprise Linux (RHEL). But as in everything else in system administration, it’s what you only think you know that can get you killed (metaphorically speaking).
Here’s the tail end of a typical limits.conf from a RHEL 6 system:
apache - nofile 65535 apache - nproc 16384 mysql - nofile 65535 mysql - nproc 16384
The Internet is replete with advice on how to do that in real life.
But things have changed a bit since the “good old days” when all Unix systems at least appeared to basically work the same (they never did, but that’s a discussion for another day).
Just as ifconfig and nslookup have been sidelined by ip [addr] and dig (or host), limits.conf has lost its primacy in the world of controlling system resources.
First Step: Check User Limits
It’s always a good idea to check your actual user limits before making configuration changes. Checking user limits is usually done by logging in as the user and running “ulimit -a”. But some users, like apache and mysql, don’t have a password or even a shell (in RHEL systems their shell is set to “/sbin/nologin”). To run ulimit as them you need to use the su command as root:
su -s /bin/sh -c 'ulimit -a' apache
This still won’t tell you what limits are in place when the service they own is started, but it’s a good place to begin.
What has not changed
The total open files limit set in sysctl.conf (or in the case of RHEL 7, in /usr/lib/sysctl.d/00-system.conf) continues to set the upper limit on the resources anyone can use. System process limits continue to be governed by kernel.threads_max.
[root@bigserv]$ sysctl -a ... fs.file-max = 810749 ... kernel.threads-max = 62742
The /etc/security/limits.conf file still does what it always did: set resource (files open and process) limits for users authenticated through PAM (Pluggable Authentication Module).
Since RHEL 6 configuration files under /etc/security/limits.d can override what appears in /etc/security/limits.conf (in RHEL 6 and RHEL 7 the default soft limit set on “*” for nproc is 1024, but this does not affect any explicitly named user, for example “apache – nproc 16384” in limits.conf will not be overridden).
For users who are logged in ulimit directives in their .bashrc cannot override what is in limits.conf.
It still does not control resource utilization by users who don’t log in, which in the case of RHEL are most system services like Apache and MySQL Server.
RHEL 4, 5 and 6
RHEL 4, 5 and 6 all used some variation on the Unix System V init system. In RHEL 6 it was upstart, made famous by its adoption in Ubuntu Linux. Service files were found under /etc/init.d.
At least as early as RHEL 5 Red Hat was telling people the proper way to vary nofiles and nproc for services was to add these parameters to the service configuration file under /etc/sysconfig like /etc/sysconfig/httpd, to avoid losing changes to /etc/init.d/httpd overwritten by updates.
ulimit -n 65536 ulimit -u 16384
(the first is for nofiles, the second, nproc)
Many applications, like MySQL Server, have their own ways of doing this outside the init system. Check their documentation for guidance (for example, you can insert the “open_files_limit=” directive in my.cnf for MySQL Server or MariaDB).
Following the adoption of systemd in the Fedora release that RHEL 7 was based on, resource allocation for services changed a bit.
In RHEL 7’s implementation of systemd service files live under /usr/lib/systemd/system.
By default systemd will look for supplemental configuration files under /usr/lib/systemd/system/[name.service].d, for example /usr/lib/systemd/system/httpd.service.d/limits.conf. There’s nothing magical about the names of these files, but it’s always a good idea to make them descriptive.
To make the same change accomplished with ulimit directives in RHEL 6 and earlier you now have to employ systemd’s own peculiar directives:
[Service] LimitNOFILE=65535 LimitNPROC=16384
(the [Service] tag is required)