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.
Importantecambia 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:
sudo sysctl -a 2>/dev/null > ~/sysctl-antes-$(date +%F).txt
Revisa los valores que vas a tocar en esta guía:
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
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:
sudo apt update
sudo apt install iperf3
En el equipo remoto, abre el puerto y arranca el servidor de pruebas:
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:
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:
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:
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:
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:
sudo nano /etc/sysctl.d/90-network-tuning.conf
Añade:
# 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:
sudo sysctl --system
Comprueba el algoritmo activo:
sysctl net.ipv4.tcp_congestion_control
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:
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:
# 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:
sudo sysctl --system
sysctl net.ipv4.tcp_rmem
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:
# 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:
somaxconnes el límite superior de la cola de conexiones pendientes. Una aplicación solo lo aprovecha si pide una cola grande enlisten(): en Nginx, por ejemplo, conlisten 443 ssl backlog=8192;.ip_local_port_rangeytcp_tw_reusesolo 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 detcp_tw_reuseen kernels recientes es2(solo para loopback);1lo extiende a todo el tráfico, y es seguro porque se apoya en las marcas de tiempo TCP.tcp_slow_start_after_idle = 0evita 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.
Advertenciano desactives las marcas de tiempo TCP (
net.ipv4.tcp_timestamps) ni busquestcp_tw_recycle. Las marcas de tiempo son necesarias paratcp_tw_reusey para la protección contra números de secuencia repetidos, ytcp_tw_recyclese 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:
cat /proc/sys/net/netfilter/nf_conntrack_count /proc/sys/net/netfilter/nf_conntrack_max
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:
echo "nf_conntrack" | sudo tee /etc/modules-load.d/conntrack.conf
sudo nano /etc/sysctl.d/91-conntrack.conf
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:
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:
iperf3 -c remote_ip -t 30
iperf3 -c remote_ip -t 30 -R
[ 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:
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:
sudo reboot
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:
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:
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.
