Skip to content

Manage Process Limits with limits.conf and systemd

On Linux, even when processes run as the same user, the configuration path for resource limits differs between a shell started from a PAM login session and a service started by systemd.

/etc/security/limits.conf and /etc/security/limits.d/*.conf are applied to login sessions by pam_limits, and the settings take effect in newly started sessions rather than existing sessions. Services started directly by systemd, on the other hand, do not pass through a PAM login session, so service-specific limits are configured with Unit settings such as LimitNOFILE=.

In this article, on an RHEL 8-compatible Linux system, we configure the following limits for the regular test user limitdemo.

  • Login shell nofile: soft 2048, hard 4096
  • Login shell nproc: soft 64, hard 128
  • systemd service nofile: soft/hard 8192

Finally, we verify that different nofile limits are actually applied to the login shell and systemd service processes even though they run as the same user.

To avoid affecting existing users, prepare a dedicated regular user. If the user already exists, creation is skipped.

Terminal window
sudo id -u limitdemo >/dev/null 2>&1 || sudo useradd --create-home --shell /bin/bash limitdemo

On Linux, nproc corresponds to RLIMIT_NPROC, which limits the number of processes, or more precisely threads, per real user ID. Because this limit does not apply in cases such as processes with a real user ID of 0, use a regular user for verification.

Step 2: Configure nofile and nproc in limits.d

Section titled “Step 2: Configure nofile and nproc in limits.d”

Create a user-specific configuration under /etc/security/limits.d/. The soft limit is the effective limit used during normal operation, while the hard limit is the maximum value to which an unprivileged process can raise the soft limit.

Terminal window
sudo tee /etc/security/limits.d/90-limitdemo.conf >/dev/null <<'EOF'
limitdemo soft nofile 2048
limitdemo hard nofile 4096
limitdemo soft nproc 64
limitdemo hard nproc 128
EOF
sudo chmod 0644 /etc/security/limits.d/90-limitdemo.conf

nofile corresponds to the number of file descriptors a process can open, while nproc corresponds to the number of processes for a user. Settings in limits.conf format are applied per login, so they do not change the limits of shells that already existed before the configuration was applied.

Step 3: Verify the limits in a new login session

Section titled “Step 3: Verify the limits in a new login session”

Use su - to start a new login session for limitdemo, then check the soft and hard limits from Bash within that session.

Terminal window
sudo su - limitdemo -c 'printf "nofile_soft=%s\nnofile_hard=%s\nnproc_soft=%s\nnproc_hard=%s\n" "$(ulimit -Sn)" "$(ulimit -Hn)" "$(ulimit -Su)" "$(ulimit -Hu)"'

If nofile_soft=2048, nofile_hard=4096, nproc_soft=64, and nproc_hard=128 are displayed, the settings have been applied to the PAM login session.

If the values do not change, check the PAM configuration for the login path you are using and confirm that pam_limits.so is called as a session module. pam_limits sets resource limits during PAM session processing.

Step 4: Configure LimitNOFILE for a systemd service

Section titled “Step 4: Configure LimitNOFILE for a systemd service”

Next, create a service that runs as the same limitdemo user. Here, sleep is used to keep the process running, and LimitNOFILE=8192 is specified.

Terminal window
sudo tee /etc/systemd/system/limitdemo.service >/dev/null <<'EOF'
[Unit]
Description=Resource limit example service
[Service]
Type=simple
User=limitdemo
ExecStart=/usr/bin/sleep 1d
LimitNOFILE=8192
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl start limitdemo.service

With systemd, resource limits for service processes can be specified through Unit settings such as LimitNOFILE=. Changing the limits.conf configuration does not define the limits for services started directly by systemd.

Step 5: Verify nofile for the running service

Section titled “Step 5: Verify nofile for the running service”

Instead of only displaying the Unit file, obtain the PID of the service that is actually running and check /proc/PID/limits, which is exposed by the kernel.

Terminal window
pid=$(sudo systemctl show --property=MainPID --value limitdemo.service)
test "$pid" -gt 0
sudo awk '$1=="Max" && $2=="open" && $3=="files" {printf "service_nofile_soft=%s\nservice_nofile_hard=%s\n",$4,$5}' "/proc/$pid/limits"

If service_nofile_soft=8192 and service_nofile_hard=8192 are displayed, LimitNOFILE=8192 has been applied to the running service process.

Step 6: Compare the effective values for the shell and service

Section titled “Step 6: Compare the effective values for the shell and service”

Finally, obtain the values from the PAM login session and the systemd service at the same time and verify that they match the intended values and differ from each other.

Terminal window
shell_soft=$(sudo su - limitdemo -c 'ulimit -Sn')
shell_hard=$(sudo su - limitdemo -c 'ulimit -Hn')
pid=$(sudo systemctl show --property=MainPID --value limitdemo.service)
service_soft=$(sudo awk '$1=="Max" && $2=="open" && $3=="files" {print $4}' "/proc/$pid/limits")
service_hard=$(sudo awk '$1=="Max" && $2=="open" && $3=="files" {print $5}' "/proc/$pid/limits")
printf 'shell_nofile=%s/%s\n' "$shell_soft" "$shell_hard"
printf 'service_nofile=%s/%s\n' "$service_soft" "$service_hard"
test "$shell_soft" = 2048
test "$shell_hard" = 4096
test "$service_soft" = 8192
test "$service_hard" = 8192
test "$shell_soft" != "$service_soft"

If the shell configured through limits.d uses 2048/4096 and the service configured through systemd uses 8192/8192, this confirms that independent limits can be set for the same user depending on the execution context.

If you want to limit the total number of tasks for an entire service, note that LimitNPROC= is based on RLIMIT_NPROC per real user ID, so other processes belonging to the same user are also counted. If the goal is per-service control, systemd’s cgroup-based TasksMax= is more appropriate.

Category: Linux