Linux limita los recursos que puede usar cada proceso: cuántos archivos puede tener abiertos, cuántos procesos puede crear un usuario o cuánta memoria puede bloquear. Los valores por defecto son conservadores y un servidor web, una base de datos o un proxy con miles de conexiones simultáneas puede agotarlos, lo que produce errores como Too many open files. En este tutorial aprenderás a consultar estos límites en Ubuntu 24.04, a diagnosticar cuándo se alcanzan y a subirlos en el lugar correcto: limits.conf para las sesiones de usuario y systemd para los servicios.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Todo lo relativo a systemd es igual en Debian 12 y Rocky Linux 9.
- Un usuario no root con privilegios
sudo. - Opcional: un servicio como Nginx para seguir el ejemplo del paso 5.
Conceptos básicos: límites blandos y duros
Cada límite tiene dos valores:
- Blando (soft): el que se aplica realmente al proceso. El propio proceso puede subirlo hasta el límite duro.
- Duro (hard): el techo. Solo root puede subirlo; un usuario normal únicamente puede bajarlo.
Los límites se heredan de proceso padre a hijo, y quién los fija al principio depende de cómo arranca el proceso:
| Cómo arranca el proceso | Quién fija sus límites |
|---|---|
| Sesión SSH o de consola | PAM, con /etc/security/limits.conf y /etc/security/limits.d/ |
| Servicio de systemd | La unidad del servicio (LimitNOFILE=, LimitNPROC=...) |
| Contenedor Docker | El demonio de Docker o la opción --ulimit |
Este es el error más común: limits.conf no afecta a los servicios de systemd. Si subes allí el límite de archivos de Nginx o MySQL y reinicias el servicio, no cambia nada.
Los límites que más se ajustan son estos:
| Recurso | Opción de ulimit | Nombre en limits.conf | Directiva de systemd |
|---|---|---|---|
| Archivos abiertos | -n | nofile | LimitNOFILE= |
| Procesos por usuario | -u | nproc | LimitNPROC= |
| Memoria bloqueada | -l | memlock | LimitMEMLOCK= |
| Tamaño de volcados de memoria | -c | core | LimitCORE= |
Paso 1: Consultar los límites actuales
Muestra todos los límites blandos de tu shell:
ulimit -a
Consulta el límite blando y el duro de archivos abiertos:
ulimit -Sn
ulimit -Hn
1024
524288
Los límites de un proceso en ejecución se leen en /proc/PID/limits. Por ejemplo, para el servicio SSH:
cat /proc/$(systemctl show -p MainPID --value ssh)/limits
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max processes 15413 15413 processes
Max open files 1024 524288 files
Max locked memory 8388608 8388608 bytes
...
Paso 2: Diagnosticar si se está alcanzando un límite
El síntoma típico en los logs de una aplicación es uno de estos mensajes:
socket() failed (24: Too many open files)
accept4() failed (24: Too many open files)
fork: retry: Resource temporarily unavailable
El código 24 es EMFILE: el proceso ha llegado a su límite de archivos abiertos. Cada socket de red cuenta como un archivo, así que un servidor con muchas conexiones lo alcanza antes que ningún otro recurso.
Cuenta los descriptores que tiene abiertos un proceso y compáralos con su límite. Sustituye PID por el identificador del proceso (lo obtienes con pgrep -f nombre o systemctl show -p MainPID --value servicio):
sudo ls /proc/PID/fd | wc -l
grep 'Max open files' /proc/PID/limits
Si el primer número se acerca al límite blando, has encontrado el problema.
Para ver el total del sistema, consulta /proc/sys/fs/file-nr. Sus tres valores son descriptores asignados, libres (siempre 0 en kernels modernos) y el máximo del sistema:
cat /proc/sys/fs/file-nr
2336 0 9223372036854775807
En Ubuntu 24.04 el máximo global es prácticamente ilimitado, así que el cuello de botella siempre es el límite por proceso.
Paso 3: Cambiar el límite en la sesión actual
ulimit modifica los límites del shell actual y de los procesos que lance, y se pierde al cerrar la sesión. Es útil para probar. Sube el límite blando con -S; sin esa opción, bash cambia a la vez el blando y el duro:
ulimit -Sn 65535
ulimit -Sn
65535
Si intentas superar el límite duro sin ser root, obtendrás ulimit: open files: cannot modify limit: Operation not permitted.
Paso 4: Hacer permanente el límite para usuarios con limits.conf
Para las sesiones SSH y de consola, el módulo pam_limits aplica lo que haya en /etc/security/limits.conf y en los archivos de /etc/security/limits.d/. Comprueba que está activo para SSH:
grep pam_limits /etc/pam.d/sshd
session required pam_limits.so
En lugar de editar limits.conf, crea un archivo propio:
sudo nano /etc/security/limits.d/90-nofile.conf
Cada línea tiene el formato dominio tipo recurso valor. El dominio puede ser un usuario, un grupo con @ delante o * para todos:
# Usuario de la aplicación
your_user soft nofile 65535
your_user hard nofile 65535
# Todos los miembros del grupo developers
@developers soft nofile 65535
@developers hard nofile 65535
# El comodín * no se aplica a root: hay que nombrarlo aparte
root soft nofile 65535
root hard nofile 65535
Sustituye your_user por tu usuario. Los cambios se aplican en las sesiones nuevas, no hay que reiniciar nada. Abre una nueva conexión SSH y compruébalo:
ulimit -Sn
ulimit -Hn
65535
65535
Paso 5: Subir el límite de un servicio de systemd
Para los servicios, el límite se define en la unidad. No edites el archivo original en /usr/lib/systemd/system/, porque una actualización del paquete lo sobrescribiría. Crea un archivo de ajustes (drop-in) con systemctl edit. Este ejemplo usa Nginx:
sudo systemctl edit nginx
Se abre un editor. Escribe el bloque entre los comentarios que indican dónde añadir contenido:
[Service]
LimitNOFILE=65535
Al guardar, systemd crea /etc/systemd/system/nginx.service.d/override.conf y recarga la configuración. Reinicia el servicio para que el nuevo límite se aplique:
sudo systemctl restart nginx
Verifica el límite que systemd aplica y el que tiene realmente el proceso:
systemctl show nginx -p LimitNOFILE
cat /proc/$(systemctl show -p MainPID --value nginx)/limits | grep 'open files'
LimitNOFILE=65535
Max open files 65535 65535 files
Algunas aplicaciones tienen además su propio ajuste. En Nginx, los procesos worker usan el valor de worker_rlimit_nofile en /etc/nginx/nginx.conf, y worker_connections debe quedar por debajo de él:
worker_rlimit_nofile 65535;
events {
worker_connections 16384;
}
Comprueba la sintaxis y recarga Nginx:
sudo nginx -t
sudo systemctl reload nginx
NotaUn valor de
LimitNOFILEmuy alto (por ejemploinfinity) no es gratis: algunos programas recorren todos los descriptores posibles al arrancar o al crear procesos hijos y se vuelven lentos. Usa un valor holgado pero realista, como 65535 o 262144.
Paso 6: Cambiar el valor por defecto de todos los servicios (opcional)
Si varios servicios necesitan el mismo límite, puedes cambiar el valor por defecto del gestor de systemd en lugar de crear un drop-in para cada uno:
sudo mkdir -p /etc/systemd/system.conf.d
sudo nano /etc/systemd/system.conf.d/limits.conf
[Manager]
DefaultLimitNOFILE=65535:524288
El formato blando:duro mantiene el límite duro que Ubuntu ya usa por defecto. Aplica el cambio recargando el gestor y reinicia los servicios afectados:
sudo systemctl daemon-reexec
sudo systemctl restart nginx
Los servicios con su propio LimitNOFILE= siguen usando el suyo.
Paso 7: Límite de procesos y TasksMax
El error fork: retry: Resource temporarily unavailable puede venir de dos límites distintos:
nproc: número máximo de procesos e hilos del mismo usuario. Se ajusta igual quenofile, connprocenlimits.doLimitNPROC=en la unidad. Por defecto ya es alto (unos 15000 en un servidor de 4 GB), así que rara vez es la causa.TasksMax: límite de procesos e hilos de systemd por servicio, mediante cgroups. Es la causa habitual en servicios que crean muchos hilos, como bases de datos o aplicaciones Java.
Consulta el límite de tareas de un servicio y cuántas usa. Sustituye your_service por su nombre:
systemctl show your_service -p TasksMax -p TasksCurrent
TasksMax=4618
TasksCurrent=187
Si TasksCurrent se acerca a TasksMax, súbelo con sudo systemctl edit your_service:
[Service]
TasksMax=16384
Después reinicia el servicio con sudo systemctl restart your_service.
Solución de problemas
El límite no cambia al conectar por SSH. Comprueba que no hay errores de sintaxis en /etc/security/limits.d/; pam_limits ignora las líneas que no entiende y lo registra en sudo journalctl -t sshd. Recuerda que el blando nunca puede superar al duro.
El límite no se aplica con sudo -u o su. Los límites dependen de la configuración PAM de cada herramienta. Para procesos permanentes, usa un servicio de systemd con LimitNOFILE= en lugar de lanzarlos desde una sesión.
El servicio sigue con 1024 después del drop-in. Revisa que el archivo tiene la cabecera [Service], ejecuta systemctl cat nombre_servicio para ver la configuración combinada y reinicia el servicio, no basta con reload.
Un contenedor Docker muestra otro límite. Los contenedores heredan los límites del demonio de Docker. Fíjalos por contenedor con docker run --ulimit nofile=65535:65535 o con la clave ulimits en Docker Compose.
Conclusión
Ya sabes leer los límites de cualquier proceso, detectar cuándo se agotan y subirlos donde corresponde: /etc/security/limits.d/ para las sesiones de usuario y LimitNOFILE o TasksMax en systemd para los servicios. Como siguientes pasos, revisa los ajustes propios de tus aplicaciones (como worker_connections en Nginx o max_connections en MySQL), ajusta los parámetros del kernel con sysctl y monitoriza el número de descriptores abiertos de tus servicios críticos.
