--- title: "Ajustar el kernel Linux con sysctl para servidores web" description: "Ajusta la cola de conexiones, BBR, los buffers TCP y los descriptores de archivo en Ubuntu 24.04 con sysctl y Nginx, y comprueba el efecto con contadores y wrk." category: "Rendimiento y Benchmarking" language: es source: https://cubepath.com/es/docs/rendimiento-y-benchmarking/ajuste-del-kernel-linux-para-servidores-web updated: 2026-09-25 --- # Ajustar el kernel Linux con sysctl para servidores web Los valores por defecto del kernel Linux funcionan bien para la mayoría de servidores, pero un servidor web con muchos clientes concurrentes puede toparse con colas de conexión que se desbordan, límites de descriptores de archivo o un control de congestión poco eficiente en enlaces con pérdidas. En este tutorial medirás primero el estado actual, aplicarás un conjunto pequeño y justificado de parámetros `sysctl` en Ubuntu 24.04, ajustarás Nginx para que aproveche los nuevos límites y comprobarás el resultado con contadores del kernel y una prueba de carga. La idea no es copiar cientos de parámetros, sino cambiar solo los que resuelven un problema medible y dejar el resto en sus valores por defecto, que en el kernel 6.8 de Ubuntu 24.04 ya son razonables. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo`. - Nginx instalado y sirviendo un sitio (`sudo apt install nginx`). Los ajustes de kernel sirven igual para Apache, Caddy o HAProxy; solo cambia la sección de configuración de la aplicación. - Opcional, para el paso 5: una segunda máquina desde la que lanzar la prueba de carga. Lanzarla desde el propio servidor mide el servidor compitiendo consigo mismo. ## Paso 1: Medir el estado actual Antes de cambiar nada, anota los valores actuales y comprueba si hay síntomas reales. Consulta los parámetros que vas a tocar: ```bash sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog net.core.netdev_max_backlog net.ipv4.tcp_congestion_control net.ipv4.ip_local_port_range ``` ```output net.core.somaxconn = 4096 net.ipv4.tcp_max_syn_backlog = 1024 net.core.netdev_max_backlog = 1000 net.ipv4.tcp_congestion_control = cubic net.ipv4.ip_local_port_range = 32768 60999 ``` El valor de `tcp_max_syn_backlog` depende de la memoria del servidor, así que puede ser distinto en el tuyo. Ahora revisa los dos contadores que indican que la cola de conexiones pendientes se ha llenado y el kernel ha descartado clientes. La herramienta `nstat` forma parte del paquete `iproute2`, instalado por defecto: ```bash nstat -az TcpExtListenOverflows TcpExtListenDrops ``` ```output #kernel TcpExtListenOverflows 0 0.0 TcpExtListenDrops 0 0.0 ``` Si estos contadores crecen durante los picos de tráfico, la cola de aceptación es demasiado pequeña. Mira también la cola de los sockets en escucha con `ss`. En un socket en estado `LISTEN`, `Send-Q` es el tamaño máximo de la cola (el backlog) y `Recv-Q` las conexiones que esperan a que la aplicación las acepte: ```bash ss -ltn 'sport = :80' ``` ```output State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 511 0.0.0.0:80 0.0.0.0:* ``` Ese `511` es el backlog que Nginx pide por defecto en Linux, aunque el kernel permita hasta 4096. Lo corregirás en el paso 4. Por último, un resumen de los estados TCP te dirá si tienes miles de conexiones en `TIME-WAIT`: ```bash ss -s ``` ## Paso 2: Crear el archivo de ajustes sysctl Los cambios con `sysctl -w` se pierden al reiniciar. Guarda los ajustes en un archivo propio dentro de `/etc/sysctl.d/`, que se carga en cada arranque: ```bash sudo nano /etc/sysctl.d/99-servidor-web.conf ``` Añade el siguiente contenido: ```ini # Cola de conexiones net.core.somaxconn = 8192 net.ipv4.tcp_max_syn_backlog = 8192 net.core.netdev_max_backlog = 16384 # Control de congestión BBR con la cola fq net.core.default_qdisc = fq net.ipv4.tcp_congestion_control = bbr # Buffers TCP: tamaño máximo de 16 MB por socket net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.ipv4.tcp_rmem = 4096 131072 16777216 net.ipv4.tcp_wmem = 4096 16384 16777216 # Conexiones keepalive y conexiones salientes net.ipv4.tcp_slow_start_after_idle = 0 net.ipv4.ip_local_port_range = 10240 65535 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = 30 ``` Qué hace cada bloque: - **Cola de conexiones**: `somaxconn` es el máximo que el kernel acepta para la cola de conexiones establecidas de cada socket en escucha, y `tcp_max_syn_backlog` el de conexiones a medio abrir (SYN recibido). `netdev_max_backlog` es la cola de paquetes que llegan por la interfaz antes de que el kernel los procese. Subirlos solo sirve si la aplicación también pide un backlog mayor, como verás en el paso 4. - **BBR y fq**: BBR es un algoritmo de control de congestión que estima el ancho de banda y la latencia del camino en lugar de reaccionar solo a la pérdida de paquetes. Suele mejorar la velocidad de descarga para clientes lejanos o en redes móviles. `fq` es la disciplina de colas recomendada para acompañarlo. - **Buffers TCP**: los tres valores de `tcp_rmem` y `tcp_wmem` son mínimo, valor inicial y máximo. El kernel ajusta cada socket de forma automática dentro de ese rango, así que subir el máximo no reserva memoria por adelantado. Un máximo de 16 MB permite aprovechar enlaces rápidos con latencia alta. - **Keepalive y salientes**: `tcp_slow_start_after_idle = 0` evita que una conexión keepalive inactiva vuelva a empezar con una ventana pequeña. `ip_local_port_range` amplía los puertos de origen disponibles para las conexiones que el servidor abre hacia backends (proxy inverso, PHP-FPM por TCP, bases de datos). Empieza en 10240 para no chocar con servicios que escuchan en puertos bajos. `tcp_tw_reuse = 1` permite reutilizar sockets en `TIME-WAIT` para nuevas conexiones salientes, y `tcp_fin_timeout` reduce el tiempo en `FIN-WAIT-2`. > Nota: no uses `net.ipv4.tcp_tw_recycle`. Rompía conexiones de clientes detrás de NAT y se eliminó del kernel en la versión 4.12, así que en Ubuntu 24.04 `sysctl` devolverá un error si lo incluyes. Antes de aplicar el archivo, confirma que el kernel tiene BBR disponible: ```bash sudo modprobe tcp_bbr sysctl net.ipv4.tcp_available_congestion_control ``` ```output net.ipv4.tcp_available_congestion_control = reno cubic bbr ``` Para que el módulo se cargue también en cada arranque, añádelo a `/etc/modules-load.d/`: ```bash echo tcp_bbr | sudo tee /etc/modules-load.d/bbr.conf ``` ## Paso 3: Aplicar y verificar los cambios Carga todos los archivos de `/etc/sysctl.d/`, igual que ocurrirá en el próximo arranque: ```bash sudo sysctl --system ``` La salida lista cada archivo leído y cada valor aplicado. Si algún parámetro no existe o tiene un formato incorrecto, verás una línea con `sysctl: cannot stat` o `Invalid argument`: corrígela antes de seguir. Comprueba los valores clave: ```bash sysctl net.core.somaxconn net.ipv4.tcp_congestion_control net.core.default_qdisc ``` ```output net.core.somaxconn = 8192 net.ipv4.tcp_congestion_control = bbr net.core.default_qdisc = fq ``` Las conexiones nuevas usarán BBR de inmediato. Puedes verlo en cualquier conexión activa, por ejemplo tu propia sesión SSH después de reconectar: ```bash ss -ti state established '( sport = :22 )' | grep -o 'bbr' ``` ```output bbr ``` La cola `fq` se aplica a las interfaces al crearse, así que la interfaz principal seguirá con la cola anterior hasta el próximo reinicio. Si quieres activarla ya sin reiniciar, sustituye `eth0` por el nombre de tu interfaz (`ip -br link` lo muestra): ```bash sudo tc qdisc replace dev eth0 root fq tc qdisc show dev eth0 ``` ```output qdisc fq 8001: root refcnt 2 limit 10000p flow_limit 100p ... ``` ## Paso 4: Ajustar Nginx a los nuevos límites El kernel limita el backlog, pero es la aplicación quien lo solicita al abrir el socket. Nginx pide 511 por defecto, así que hay que indicarle el nuevo valor en la directiva `listen`. Abre el bloque `server` de tu sitio: ```bash sudo nano /etc/nginx/sites-available/default ``` Añade el parámetro `backlog` a las directivas `listen`: ```nginx server { listen 80 default_server backlog=8192; listen [::]:80 default_server backlog=8192; # ... resto de la configuración } ``` > Importante: `backlog` solo puede aparecer una vez por cada combinación de dirección y puerto. Si tienes varios bloques `server` en el puerto 80, ponlo solo en el que lleva `default_server`. El segundo límite habitual son los descriptores de archivo: cada conexión de cliente consume uno, y si Nginx actúa como proxy consume dos. El servicio de systemd arranca con un límite blando de 1024. Sube el límite de los workers y el número de conexiones en `/etc/nginx/nginx.conf`: ```bash sudo nano /etc/nginx/nginx.conf ``` Ajusta estas directivas (la primera va en el contexto principal, fuera de cualquier bloque; `worker_connections` ya existe dentro de `events`): ```nginx worker_processes auto; worker_rlimit_nofile 65535; events { worker_connections 16384; } ``` `worker_rlimit_nofile` eleva el límite de cada worker sin tocar la unidad de systemd, y `worker_connections` debe quedar por debajo de él. Valida la configuración y recarga Nginx: ```bash sudo nginx -t sudo systemctl reload nginx ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` Comprueba que el socket usa el nuevo backlog: ```bash ss -ltn 'sport = :80' ``` ```output State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 8192 0.0.0.0:80 0.0.0.0:* ``` Y que los workers tienen el límite de descriptores ampliado: ```bash grep 'Max open files' /proc/$(pgrep -f 'nginx: worker' | head -n 1)/limits ``` ```output Max open files 65535 65535 files ``` ## Paso 5: Probar bajo carga La herramienta `wrk` genera muchas conexiones HTTP concurrentes con poco consumo de recursos. Instálala en la máquina cliente: ```bash sudo apt install wrk ``` Lanza una prueba de 30 segundos con 4 hilos y 2000 conexiones abiertas contra `your_server_ip`: ```bash wrk -t4 -c2000 -d30s --latency http://your_server_ip/ ``` ```output Running 30s test @ http://your_server_ip/ 4 threads and 2000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 38.12ms 21.44ms 412.30ms 81.02% Req/Sec 13.40k 1.52k 17.90k 72.11% Latency Distribution 50% 34.80ms 99% 118.66ms 1599208 requests in 30.04s, 1.28GB read Requests/sec: 53236.18 ``` Si el cliente se queja de `Too many open files`, sube su propio límite antes de lanzar la prueba con `ulimit -n 65535`. Mientras dura la prueba, vuelve a mirar en el servidor los contadores del paso 1: ```bash nstat -az TcpExtListenOverflows TcpExtListenDrops ``` Si siguen en 0 (o crecen mucho menos que antes de los cambios) y la columna `Socket errors` de `wrk` no muestra `connect` ni `timeout`, la cola de conexiones ya no es el cuello de botella. A partir de aquí, las mejoras vendrán de la aplicación: caché, compresión, número de workers de PHP-FPM o del backend. ## Solución de problemas **`sysctl: cannot stat /proc/sys/net/...: No such file or directory`**: el parámetro no existe en este kernel (típico de `tcp_tw_recycle`) o tiene una errata. Elimínalo del archivo y vuelve a ejecutar `sudo sysctl --system`. **`tcp_congestion_control` vuelve a `cubic` tras reiniciar**: el módulo `tcp_bbr` no se cargó antes de aplicar sysctl. Comprueba que existe `/etc/modules-load.d/bbr.conf` y que `lsmod | grep tcp_bbr` muestra el módulo. **Nginx no arranca tras añadir `backlog`**: `nginx -t` mostrará `duplicate listen options for 0.0.0.0:80`. El parámetro está repetido en varios bloques `server` del mismo puerto; déjalo solo en uno. **`Recv-Q` crece en el socket en escucha aunque el backlog sea grande**: la aplicación no acepta conexiones al ritmo al que llegan. El problema está en los workers (CPU saturada, backend lento), no en el kernel. ## Conclusión Has medido la cola de conexiones del servidor, aplicado un conjunto persistente de ajustes `sysctl` con BBR, buffers TCP más amplios y un backlog mayor, y has configurado Nginx para aprovecharlo. La clave es repetir la medición del paso 1 tras cada cambio: si un contador no se mueve, el ajuste no hacía falta. Como siguientes pasos, puedes revisar la gestión de memoria y swap del servidor, habilitar HTTP/2 y la caché de Nginx, o ajustar el programador de E/S si el servidor también sirve mucho contenido desde disco.