Troubleshooting Persistent ulimit -n 1024 Issue Despite Proper limits.conf Configuration on Ubuntu


1 views

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