LFCS 138 ๐ง System Resource Limits โ ulimit
The previous chapters covered disk usage and I/O performance. This chapter covers the limits that constrain how much of those resources a process can consume. The ulimit command is the shell builtin that reads and sets the resource limits for the current shell and the processes it spawns. The LFCS exam tests the distinction between soft and hard limits, the specific flags for the common resources (-n for open files, -u for processes, -s for stack size), and the mechanism for making limits persistent. The critical trap is that ulimit is a per-session setting. A change made with ulimit -n 65535 applies only to the current shell and its children. When the shell exits, the change is gone. The persistent configuration requires /etc/security/limits.conf (for login users) or a systemd unit override (for services).
Key point: The ulimit command sets limits for the current shell. The -H flag sets the hard limit, and the -S flag sets the soft limit. A non-root user can lower the hard limit but cannot raise it. A non-root user can raise the soft limit up to the hard limit. The -a flag shows all current limits. The /etc/security/limits.conf file makes the limits persistent for login sessions via PAM. Systemd services do not read limits.conf and require LimitNOFILE= (or the equivalent) in the unit file.
Why resource limits require a specific mental model
The soft versus hard problem. A soft limit is the current enforcement value. A hard limit is the ceiling that the soft limit cannot exceed. A non-root user can raise the soft limit up to the hard limit, but cannot raise the hard limit. A root user can raise both. The ulimit -Sn shows the soft limit, ulimit -Hn shows the hard limit, and ulimit -n (without a flag) shows the soft limit by default .
The per-session problem. ulimit is a shell builtin. It modifies the limits of the current shell process and the processes it forks. A new shell (a new SSH session, a new terminal) starts with the limits defined in the system configuration. The ulimit command does not modify the system configuration; it modifies the running process. The persistent configuration is the /etc/security/limits.conf file or the systemd unit .
The PAM problem. The /etc/security/limits.conf file is read by the pam_limits module at login. The module sets the limits for the user’s session. If the PAM configuration does not include session required pam_limits.so, the limits.conf file is ignored. On most distributions, this line is included by default in /etc/pam.d/common-session or the equivalent .
The systemd problem. Systemd services do not read /etc/security/limits.conf. A service that needs a higher open-file limit must have the limit set in its unit file with LimitNOFILE=65535 (or the equivalent for other resources). The systemctl edit command creates an override file. The systemctl daemon-reload and systemctl restart commands apply the change .
The trade-off. ulimit is simple for a quick check or a temporary adjustment. The persistent configuration is more complex because it depends on the session type: login users use limits.conf, and services use systemd. The exam tests the ulimit syntax and the distinction between the temporary and persistent configuration.
a. The ulimit syntax and common flags
The ulimit command is a builtin. The -a flag shows all limits. The -H and -S flags select the hard or soft limit. The resource flags select the specific resource.
# Show all limits
ulimit -a
# Show the soft limit for open files
ulimit -Sn
# Show the hard limit for open files
ulimit -Hn
# Set the soft limit for open files
ulimit -n 4096
# Set both soft and hard
ulimit -n 65535
The resource flags are:
| Flag | Resource |
|---|---|
-n | Open files |
-u | Max user processes |
-s | Stack size (KB) |
-c | Core file size (blocks) |
-f | File size (blocks) |
-v | Virtual memory (KB) |
-t | CPU time (seconds) |
The ulimit -a output shows the resource name, the soft limit, and the unit. The -n is the most commonly tested because the open-file limit is the one that most often causes application failures (e.g., a web server that cannot accept new connections because it has reached the limit) .
b. Making limits persistent with limits.conf
The /etc/security/limits.conf file is the configuration for the pam_limits module. The syntax is <domain> <type> <item> <value>.
# /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
@developers soft nproc 4096
@developers hard nproc 8192
The <domain> is the user, the group (prefixed with @), or * for all users. The <type> is soft, hard, or - for both. The <item> is the resource name (nofile, nproc, stack, core, etc.). The <value> is the limit .
The limits.conf file is not the only source. The /etc/security/limits.d/ directory contains additional configuration files. The files are read in alphabetical order, and the last matching rule wins. A file in limits.d/ can override a rule in limits.conf .
After modifying limits.conf, the user must log out and log back in for the change to take effect. The su and sudo commands do not re-read the limits unless the PAM configuration is set up to do so. The ulimit -n command in a new session confirms the new value .
c. Systemd services and the LimitNOFILE directive
Systemd services do not read limits.conf. The limits are set in the unit file with the Limit* directives.
# Override for a specific service
sudo systemctl edit nginx
# Add:
[Service]
LimitNOFILE=65535
LimitNPROC=65535
# Apply
sudo systemctl daemon-reload
sudo systemctl restart nginx
The LimitNOFILE directive sets the open-file limit. The LimitNPROC sets the process limit. The LimitCORE sets the core file size. The LimitSTACK sets the stack size. The Limit* directives accept infinity as a value .
The global default for all services is set in /etc/systemd/system.conf with DefaultLimitNOFILE=. The user session default is in /etc/systemd/user.conf with the same directive. The systemctl daemon-reexec command applies the global change without a full reboot .
The cat /proc/<PID>/limits command shows the limits of a running process. This is the verification step: the ulimit in the shell may show one value, but the service process may have a different value because systemd applied the unit file directive .
Complete Example Session
# ============================================
# PART 1: VIEW CURRENT LIMITS
# ============================================
ulimit -a
# Shows all limits for the current shell.
# ============================================
# PART 2: VIEW OPEN FILE LIMITS
# ============================================
ulimit -Sn
# Soft limit: 1024
ulimit -Hn
# Hard limit: 4096
# ============================================
# PART 3: SET A SOFT LIMIT
# ============================================
ulimit -n 2048
ulimit -Sn
# Soft limit: 2048
# ============================================
# PART 4: ATTEMPT TO RAISE THE HARD LIMIT
# ============================================
ulimit -Hn 8192
# Error: cannot raise limit (non-root)
# ============================================
# PART 5: PERSISTENT LIMIT FOR LOGIN USERS
# ============================================
sudo tee -a /etc/security/limits.conf <<'EOF'
* soft nofile 65535
* hard nofile 65535
EOF
# ============================================
# PART 6: VERIFY PAM IS ENABLED
# ============================================
grep pam_limits /etc/pam.d/common-session
# session required pam_limits.so
# ============================================
# PART 7: RE-LOGIN AND VERIFY
# ============================================
# Log out and log back in.
ulimit -n
# 65535
# ============================================
# PART 8: SYSTEMD SERVICE OVERRIDE
# ============================================
sudo systemctl edit nginx
# [Service]
# LimitNOFILE=65535
sudo systemctl daemon-reload
sudo systemctl restart nginx
# ============================================
# PART 9: VERIFY SERVICE LIMITS
# ============================================
cat /proc/$(pgrep nginx | head -1)/limits | grep "open files"
# Max open files 65535
The nine parts trace the resource limits: view, soft/hard check, set soft, attempt hard raise, persistent login limit, PAM check, re-login verification, systemd override, and service verification.
Quick Reference
ulimit Flags
| Flag | Resource |
|---|---|
-a | All limits |
-H | Hard limit |
-S | Soft limit |
-n | Open files |
-u | Max user processes |
-s | Stack size (KB) |
-c | Core file size (blocks) |
-f | File size (blocks) |
-v | Virtual memory (KB) |
limits.conf Syntax
| Field | Meaning |
|---|---|
<domain> | User, @group, or * |
<type> | soft, hard, or - |
<item> | Resource name (nofile, nproc) |
<value> | Limit value |
Persistent Configuration
| Scope | Location |
|---|---|
| Login users | /etc/security/limits.conf |
| Drop-in | /etc/security/limits.d/*.conf |
| Systemd service | systemctl edit <service> |
| Systemd global | /etc/systemd/system.conf |
Systemd Directives
| Directive | Resource |
|---|---|
LimitNOFILE | Open files |
LimitNPROC | Processes |
LimitCORE | Core file size |
LimitSTACK | Stack size |
Best Practices
โ Do This:
ulimit -a
<!-- Check current limits before changing --> # โ
sudo systemctl edit nginx
<!-- Override limits for a systemd service --> # โ
cat /proc/<PID>/limits
<!-- Verify the process's actual limits --> # โ
โ Don’t Do This:
# Assume ulimit changes are persistent
<!-- They apply only to the current shell --> # โ
# Add limits.conf entries for systemd services
<!-- Systemd does not read limits.conf --> # โ
# Set the soft limit above the hard limit
<!-- Not permitted for non-root users --> # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
ulimit change lost after logout | Per-session setting | Use limits.conf |
limits.conf not applied | PAM not enabled or no re-login | Check PAM, log out and back in |
| Systemd service limit ignored | limits.conf not read by systemd | Use LimitNOFILE |
| Soft limit cannot be raised | Hard limit is too low | Raise hard limit as root |
| Application cannot open files | nofile limit reached | Increase nofile |
Real-World Examples
1. View All Limits
ulimit -a
2. View Soft Limit
ulimit -Sn
3. View Hard Limit
ulimit -Hn
4. Set Soft Limit
ulimit -n 4096
5. Persistent Login Limit
* soft nofile 65535
6. Group Limit
@developers hard nproc 8192
7. Systemd Override
systemctl edit nginx
# LimitNOFILE=65535
8. Systemd Global
DefaultLimitNOFILE=65535
9. Verify Service
cat /proc/<PID>/limits
10. PAM Check
grep pam_limits /etc/pam.d/common-session
Visual
Soft vs Hard Limit
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Hard limit (4096) โ
โ โโโ Ceiling for soft limit โ
โ โ
โ Soft limit (1024) โ
โ โโโ Current enforcement โ
โ โ
โ Non-root user can raise soft up to hard โ
โ Non-root user cannot raise hard โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Persistent Configuration Paths
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Login user โ
โ โ /etc/security/limits.conf โ
โ โ PAM reads at login โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Systemd service โ
โ โ systemctl edit <service> โ
โ โ LimitNOFILE=65535 โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Verify: cat /proc/<PID>/limits โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Current shell limits | ulimit -a |
| Soft limit | ulimit -S |
| Hard limit | ulimit -H |
| Open files | -n |
| Max processes | -u |
| Persistent login | /etc/security/limits.conf |
| PAM module | pam_limits.so |
| Systemd service | LimitNOFILE= |
| Verify process | /proc/<PID>/limits |
Key takeaways:
ulimitis a shell builtin. It modifies the limits of the current shell and its children. The change is lost when the shell exits. The persistent configuration islimits.conffor login users and systemd units for services .- Soft limits are the enforcement value; hard limits are the ceiling. A non-root user can raise the soft limit up to the hard limit but cannot raise the hard limit. A root user can raise both .
limits.confis read by PAM at login. Thepam_limits.somodule must be enabled in the PAM configuration. The change takes effect on the next login, not immediately .- Systemd services do not read
limits.conf. A service that needs a higher limit must have theLimitNOFILE(or equivalent) directive in its unit file, applied withsystemctl daemon-reloadandsystemctl restart. - The verification is
/proc/<PID>/limits. Theulimitcommand in the shell shows the shell’s limits. The/procfile shows the actual limits of a specific process, which may differ if systemd applied a directive .
Remember: ulimit is the per-session tool. limits.conf is the login-user persistence. Systemd Limit* directives are the service persistence. The soft limit is the current value. The hard limit is the ceiling. The -a flag shows everything. The -n flag is the open-file limit, which is the one that most often causes application failures.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!