--- title: "Cómo optimizar TCP con sysctl y BBR en Ubuntu 24.04" description: "Ajusta la pila TCP del kernel con sysctl en Ubuntu 24.04: activa BBR, dimensiona los búferes según el BDP, amplía colas y conntrack y mide la mejora con iperf3." category: "Temas Avanzados" language: es source: https://cubepath.com/es/docs/temas-avanzados/ajuste-avanzado-de-tcp-ip-con-sysctl updated: 2026-09-25 --- # Cómo optimizar TCP con sysctl y BBR en Ubuntu 24.04 El kernel de Linux trae valores de red pensados para funcionar razonablemente en cualquier equipo, desde un portátil hasta un servidor. En un servidor con mucho tráfico o que transfiere datos a clientes lejanos, algunos de esos valores limitan el rendimiento: búferes TCP pequeños para enlaces con mucha latencia, un control de congestión que reacciona mal a la pérdida de paquetes o colas que se desbordan en picos de conexiones. En esta guía medirás el punto de partida, aplicarás un conjunto de ajustes justificados con `sysctl` en Ubuntu 24.04, activarás BBR y comprobarás la mejora con `iperf3`. ## Requisitos previos Necesitas: - Un servidor con Ubuntu 24.04 LTS (kernel 6.8 o posterior), por ejemplo un VPS de CubePath, con un usuario no root con privilegios `sudo`. - Un segundo equipo, idealmente en otra región o con una latencia de varias decenas de milisegundos, para medir el rendimiento. - Conocer el tipo de carga del servidor (servidor web, proxy, transferencia de archivos, base de datos). No hay un ajuste universal y no todos los cambios convienen a todas las cargas. > Importante: cambia los parámetros de uno en uno o por bloques pequeños y mide después de cada cambio. Copiar listas enormes de valores de Internet suele empeorar el rendimiento o el uso de memoria, y hace imposible saber qué ayudó. ## Paso 1: Guardar la configuración actual y medir Guarda una copia de todos los valores actuales del kernel para poder compararlos o volver atrás: ```bash sudo sysctl -a 2>/dev/null > ~/sysctl-antes-$(date +%F).txt ``` Revisa los valores que vas a tocar en esta guía: ```bash sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc \ net.core.rmem_max net.core.wmem_max net.ipv4.tcp_rmem net.ipv4.tcp_wmem \ net.core.somaxconn net.ipv4.tcp_max_syn_backlog net.ipv4.ip_local_port_range ``` ```output net.ipv4.tcp_congestion_control = cubic net.core.default_qdisc = fq_codel net.core.rmem_max = 212992 net.core.wmem_max = 212992 net.ipv4.tcp_rmem = 4096 131072 6291456 net.ipv4.tcp_wmem = 4096 16384 4194304 net.core.somaxconn = 4096 net.ipv4.tcp_max_syn_backlog = 1024 net.ipv4.ip_local_port_range = 32768 60999 ``` Instala `iperf3` en ambos equipos para medir el caudal: ```bash sudo apt update sudo apt install iperf3 ``` En el equipo remoto, abre el puerto y arranca el servidor de pruebas: ```bash sudo ufw allow 5201/tcp iperf3 -s ``` Desde tu servidor, mide la latencia y después el caudal con un solo flujo TCP, que es lo que más depende de los ajustes del kernel. Sustituye `remote_ip` por la IP del equipo remoto: ```bash ping -c 10 remote_ip | tail -n 1 iperf3 -c remote_ip -t 30 iperf3 -c remote_ip -t 30 -R ``` La opción `-R` mide en sentido inverso (el remoto envía y tu servidor recibe). Anota la latencia media y los dos resultados: ```output rtt min/avg/max/mdev = 98.112/98.420/99.031/0.254 ms [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-30.00 sec 1.62 GBytes 464 Mbits/sec 1204 sender ``` ## Paso 2: Activar BBR como control de congestión El algoritmo de control de congestión decide a qué ritmo envía datos TCP. CUBIC, el predeterminado, reduce el ritmo drásticamente ante cualquier pérdida de paquetes. BBR, desarrollado por Google, estima el ancho de banda y la latencia reales del camino y suele conseguir bastante más caudal en enlaces largos o con algo de pérdida, sin llenar las colas de los routers. Solo afecta al tráfico que envía tu servidor. Comprueba qué algoritmos están disponibles: ```bash sysctl net.ipv4.tcp_available_congestion_control ``` Si `bbr` no aparece en la lista, carga el módulo y haz que se cargue en cada arranque: ```bash sudo modprobe tcp_bbr echo "tcp_bbr" | sudo tee /etc/modules-load.d/bbr.conf ``` Crea un archivo propio en `/etc/sysctl.d/`, que se aplica al arrancar y no se sobrescribe con las actualizaciones del sistema: ```bash sudo nano /etc/sysctl.d/90-network-tuning.conf ``` Añade: ```ini # Congestion control: BBR with the fq packet scheduler for pacing net.core.default_qdisc = fq net.ipv4.tcp_congestion_control = bbr ``` La disciplina de colas `fq` realiza el espaciado de paquetes (*pacing*) en el que se apoya BBR. Aplica los cambios: ```bash sudo sysctl --system ``` Comprueba el algoritmo activo: ```bash sysctl net.ipv4.tcp_congestion_control ``` ```output net.ipv4.tcp_congestion_control = bbr ``` El cambio de `default_qdisc` solo se aplica a las interfaces que se inicializan después, así que reinicia el servidor o ejecuta `sudo tc qdisc replace dev eth0 root fq` (cambiando `eth0` por tu interfaz) para aplicarlo ya. Mientras corre una prueba de `iperf3`, puedes confirmar que la conexión usa BBR: ```bash ss -ti dst remote_ip | grep -o 'bbr' ``` ## Paso 3: Dimensionar los búferes TCP TCP solo puede tener en vuelo, sin confirmar, tantos datos como le permita el búfer. La cantidad necesaria para llenar un enlace es el **producto ancho de banda por retardo** (BDP): ancho de banda en bytes por segundo multiplicado por la latencia de ida y vuelta. | Enlace | Latencia (RTT) | BDP | |---|---|---| | 1 Gbit/s | 10 ms | 1,25 MB | | 1 Gbit/s | 100 ms | 12,5 MB | | 10 Gbit/s | 100 ms | 125 MB | El máximo por defecto de Ubuntu para recepción es 6 MB, que limita un único flujo a unos 480 Mbit/s con 100 ms de latencia, justo lo que muestra la medición del paso 1. Añade estas líneas a `/etc/sysctl.d/90-network-tuning.conf`: ```ini # TCP buffers: min, default, max (bytes). The kernel autotunes between them. net.ipv4.tcp_rmem = 4096 131072 33554432 net.ipv4.tcp_wmem = 4096 16384 33554432 # Upper limit for buffers requested explicitly by applications (SO_RCVBUF/SO_SNDBUF) net.core.rmem_max = 33554432 net.core.wmem_max = 33554432 ``` Con un máximo de 32 MB, un flujo puede llegar a unos 2,5 Gbit/s con 100 ms de latencia. Solo se sube el valor máximo: el kernel sigue asignando búferes pequeños a cada conexión y los hace crecer bajo demanda (*autotuning*), así que un servidor con miles de conexiones lentas no consume más memoria. Para enlaces de 10 Gbit/s o más con clientes lejanos, sube el máximo a 64 o 128 MB. Aplica y comprueba: ```bash sudo sysctl --system sysctl net.ipv4.tcp_rmem ``` ```output net.ipv4.tcp_rmem = 4096 131072 33554432 ``` ## Paso 4: Ajustar colas y conexiones Estos parámetros importan en servidores que aceptan o abren muchas conexiones por segundo, como un proxy inverso, un balanceador o una API muy concurrida. Añádelos al mismo archivo: ```ini # Pending connections waiting for accept() per listening socket net.core.somaxconn = 8192 # Half-open connections (SYN received) waiting for the handshake to finish net.ipv4.tcp_max_syn_backlog = 8192 # Packets queued per CPU when the NIC delivers faster than the kernel processes net.core.netdev_max_backlog = 16384 # Local ports for outbound connections (proxies to backends, clients to databases) net.ipv4.ip_local_port_range = 10240 65535 # Reuse TIME_WAIT sockets for new outbound connections when safe net.ipv4.tcp_tw_reuse = 1 # Do not shrink the congestion window after a connection has been idle net.ipv4.tcp_slow_start_after_idle = 0 # Probe the path MTU when packets are silently dropped (broken PMTUD) net.ipv4.tcp_mtu_probing = 1 ``` Por qué cada uno: - `somaxconn` es el límite superior de la cola de conexiones pendientes. Una aplicación solo lo aprovecha si pide una cola grande en `listen()`: en Nginx, por ejemplo, con `listen 443 ssl backlog=8192;`. - `ip_local_port_range` y `tcp_tw_reuse` solo afectan a conexiones **salientes**. Un proxy que abre miles de conexiones por segundo hacia sus backends puede quedarse sin puertos libres por culpa de los sockets en TIME_WAIT. El valor por defecto de `tcp_tw_reuse` en kernels recientes es `2` (solo para loopback); `1` lo extiende a todo el tráfico, y es seguro porque se apoya en las marcas de tiempo TCP. - `tcp_slow_start_after_idle = 0` evita que las conexiones keep-alive (HTTP/2, bases de datos) vuelvan a empezar despacio tras unos segundos de inactividad. Aplica los cambios con `sudo sysctl --system` y comprueba cualquiera de ellos con `sysctl nombre.del.parametro`. > Advertencia: no desactives las marcas de tiempo TCP (`net.ipv4.tcp_timestamps`) ni busques `tcp_tw_recycle`. Las marcas de tiempo son necesarias para `tcp_tw_reuse` y para la protección contra números de secuencia repetidos, y `tcp_tw_recycle` se eliminó del kernel en la versión 4.12 porque rompía conexiones de clientes detrás de NAT. ## Paso 5: Ampliar la tabla de conntrack (solo si usas NAT o un cortafuegos con estado) Si el servidor usa UFW, Docker o reglas de NAT, el kernel registra cada conexión en la tabla de seguimiento de conexiones (conntrack). Cuando se llena, descarta paquetes nuevos y en el registro del kernel aparece `nf_conntrack: table full, dropping packet`. Comprueba el uso actual y el máximo: ```bash cat /proc/sys/net/netfilter/nf_conntrack_count /proc/sys/net/netfilter/nf_conntrack_max ``` ```output 1824 262144 ``` Si `/proc/sys/net/netfilter/` no existe, el módulo no está cargado y no necesitas este paso. Si el uso se acerca al máximo en horas punta, amplíalo. Cada entrada ocupa unos 300 bytes, así que un millón de entradas son unos 300 MB de RAM. Como el parámetro solo existe cuando el módulo `nf_conntrack` está cargado, crea un archivo aparte y asegúrate de que el módulo se carga al arrancar: ```bash echo "nf_conntrack" | sudo tee /etc/modules-load.d/conntrack.conf sudo nano /etc/sysctl.d/91-conntrack.conf ``` ```ini net.netfilter.nf_conntrack_max = 1048576 # Established connections idle for longer than 1 day are forgotten (default is 5 days) net.netfilter.nf_conntrack_tcp_timeout_established = 86400 ``` Aplica y comprueba: ```bash sudo sysctl --system sysctl net.netfilter.nf_conntrack_max ``` ## Paso 6: Medir de nuevo y comparar Con todos los cambios aplicados, repite exactamente las mismas pruebas del paso 1 contra el mismo equipo remoto: ```bash iperf3 -c remote_ip -t 30 iperf3 -c remote_ip -t 30 -R ``` ```output [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-30.00 sec 6.21 GBytes 1.78 Gbits/sec 312 sender ``` En enlaces con latencia alta, la mejora de un solo flujo suele ser grande; en una red local con 1 ms de latencia, apenas habrá diferencia porque los valores por defecto ya bastaban. Revisa también las retransmisiones globales del sistema: ```bash nstat -az TcpRetransSegs TcpOutSegs ``` Una proporción de retransmisiones por encima del 1-2 % de los segmentos enviados indica un problema en la red, no en la configuración del kernel. Por último, reinicia el servidor y comprueba que todos los valores se mantienen: ```bash sudo reboot ``` ```bash sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc net.ipv4.tcp_rmem ``` ## Revisar la tarjeta de red (opcional) En servidores físicos con mucho tráfico, las colas de la propia tarjeta de red (*ring buffers*) también pueden desbordarse. Instala `ethtool` y consulta el tamaño actual y el máximo admitido: ```bash sudo apt install ethtool sudo ethtool -g eth0 ``` Si los contadores de descartes crecen (`ip -s link show eth0`, columna `dropped`) y el tamaño actual está por debajo del máximo, amplíalo, por ejemplo con `sudo ethtool -G eth0 rx 4096`. Este cambio no es persistente; para mantenerlo tras reiniciar, configúralo en Netplan o en una unidad de systemd. En una VM con `virtio-net` muchos de estos parámetros no se pueden modificar, y no suele hacer falta. ## Solución de problemas **`sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_max`.** El módulo `nf_conntrack` no está cargado. Cárgalo con `sudo modprobe nf_conntrack` o elimina ese archivo si no usas NAT ni un cortafuegos con estado. **El algoritmo vuelve a `cubic` tras reiniciar.** El módulo `tcp_bbr` no se cargó antes de aplicar los sysctl. Comprueba que existe `/etc/modules-load.d/bbr.conf` y que otro archivo de `/etc/sysctl.d/` con un número mayor no sobrescribe el valor: `grep -r congestion /etc/sysctl.d/ /etc/sysctl.conf`. **El caudal no mejora.** El límite puede estar en otra parte: el plan de red del servidor, el equipo remoto (que también necesita búferes grandes para recibir), la CPU (un solo núcleo al 100 % durante la prueba) o el cifrado de la aplicación. Prueba con varios flujos (`iperf3 -c remote_ip -P 4`) para ver si el enlace da más de sí. **Quieres deshacer todos los cambios.** Elimina los archivos que has creado y reinicia: ```bash sudo rm /etc/sysctl.d/90-network-tuning.conf /etc/sysctl.d/91-conntrack.conf /etc/modules-load.d/bbr.conf /etc/modules-load.d/conntrack.conf sudo reboot ``` ## Conclusión Has activado BBR, dimensionado los búferes TCP según el BDP de tus enlaces, ampliado las colas de conexión y conntrack, y comprobado el efecto con mediciones antes y después. Mantén estos ajustes en un único archivo de `/etc/sysctl.d/` versionado junto al resto de tu configuración. Como siguientes pasos puedes ajustar la directiva `backlog` de Nginx o HAProxy para aprovechar el nuevo `somaxconn`, vigilar las retransmisiones y el uso de conntrack desde tu sistema de monitorización, o aplicar los mismos ajustes a todos tus servidores con Ansible.