When attempting to increase open file descriptor limits on Ubuntu systems, many administrators encounter situations where changes to /etc/security/limits.conf
don't take effect, particularly with non-interactive shells or services. The system stubbornly maintains the default 1024 limit despite proper configuration.
First, ensure all critical components are properly configured:
# /etc/security/limits.conf contents
* soft nofile 100000
* hard nofile 100000
root soft nofile 100000
root hard nofile 100000
And system-wide limit in sysctl:
# /etc/sysctl.conf entry
fs.file-max = 200000
The default /bin/sh
(which is typically symlinked to dash on Ubuntu) behaves differently than bash for reading limits. For systems using /bin/sh
, we need additional configuration in /etc/pam.d/common-session
:
session required pam_limits.so
Modern Ubuntu versions using systemd require additional configuration:
# Create or modify /etc/systemd/system.conf
DefaultLimitNOFILE=100000
# Then reload systemd
systemctl daemon-reload
To properly test the changes, avoid checking limits in the same session where you made changes. Instead:
# Start new login session
sudo su - $USER
# Check hard limit
ulimit -Hn
# Check soft limit
ulimit -Sn
# Check system-wide maximum
cat /proc/sys/fs/file-max
For specific services, you can override limits in their unit files:
[Service]
LimitNOFILE=100000
Or set per-process limits using prlimit
:
prlimit --pid $PID --nofile=100000:100000
To trace how limits are being applied:
strace -e trace=open,openat bash -c "ulimit -n" 2>&1 | grep limits
Check which PAM modules are loaded:
grep -r pam_limits.so /etc/pam.d/
When your carefully configured /etc/security/limits.conf
settings refuse to apply despite proper syntax and PAM configuration, several sneaky culprits might be at play. Let's dissect this systematically.
The /bin/sh
shell (typically dash on Ubuntu) handles limits differently than bash. Test with:
# Check if pam_limits is loaded
grep -r pam_limits.so /etc/pam.d
# Verify shell interpreter
ls -l /bin/sh
For non-login shells (like SSH commands), certain PAM modules may not trigger. Create a test PAM configuration:
# /etc/pam.d/custom_sshd
session required pam_limits.so
session required pam_env.so
Modern Ubuntu systems use systemd which ignores limits.conf
for services. Create override files:
# /etc/systemd/system.conf.d/limits.conf
[Manager]
DefaultLimitNOFILE=100000
Ensure kernel-level limits aren't capping your changes:
# Current kernel limit
cat /proc/sys/fs/file-max
# Temporary adjustment
sysctl -w fs.file-max=100000
Some systems require explicit root declarations in both files:
# /etc/security/limits.d/90-override.conf
root soft nofile 100000
root hard nofile 100000
Trace the limit-setting process:
strace -f -e trace=open,stat bash -c "ulimit -n"
Bypass shell limitations with direct process inspection:
# Check actual process limits
cat /proc/$$/limits
# Test with privileged user
sudo -i ulimit -n
When all else fails, enforce limits via profile scripts:
# /etc/profile.d/ulimit.sh
ulimit -n 100000