--- title: "Cómo configurar un firewall con nftables en Ubuntu 24.04" description: "Crea un firewall con nftables en Ubuntu 24.04 con conjuntos, límite de SSH por IP y registro, aplícalo con reversión automática y migra reglas de iptables." category: "Configuración de Red" language: es source: https://cubepath.com/es/docs/configuración-de-red/configuracion-de-nftables-sucesor-de-iptables updated: 2026-09-25 --- # Cómo configurar un firewall con nftables en Ubuntu 24.04 nftables es el sustituto de iptables en el kernel Linux: una sola herramienta (`nft`) y una sola sintaxis para IPv4, IPv6, ARP y bridges, con conjuntos y mapas nativos que evitan repetir reglas. En este tutorial escribirás un firewall de entrada completo en `/etc/nftables.conf` para un servidor con SSH y web en Ubuntu 24.04, lo aplicarás con un mecanismo de reversión automática, lo gestionarás en caliente y verás cómo traducir reglas antiguas de iptables. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. En Debian 12 los pasos son idénticos; en Rocky Linux 9 el servicio y el archivo son los mismos, pero el firewall por defecto es firewalld y debes desactivarlo antes. - Un usuario no root con privilegios `sudo`. - Acceso a la consola del servidor (VNC o consola web del proveedor) por si pierdes la conexión SSH. - Conocer los puertos que debe ofrecer el servidor. En el ejemplo: SSH (22), HTTP (80) y HTTPS (443). > Importante: usa un solo gestor de firewall. UFW y las reglas de `iptables` también crean tablas en nftables y mezclarlas con un ruleset propio produce resultados difíciles de depurar. Si el servidor ejecuta Docker, ten en cuenta que Docker crea sus propias reglas; no uses `flush ruleset` en ese caso sin revisar antes cómo convivirán. ## Paso 1: Instalar nftables y desactivar UFW Instala el paquete, que incluye la herramienta `nft`, el archivo `/etc/nftables.conf` y el servicio que lo carga en el arranque: ```bash sudo apt update sudo apt install nftables ``` Comprueba la versión: ```bash sudo nft --version ``` ```output nftables v1.0.9 (Old Doc Yellowstone) ``` Si UFW está activo, desactívalo: ```bash sudo ufw disable ``` Revisa qué reglas hay cargadas ahora mismo. En un sistema limpio la salida estará vacía: ```bash sudo nft list ruleset ``` ## Paso 2: Entender la estructura de nftables nftables no trae tablas ni cadenas predefinidas como iptables: las creas tú. La jerarquía es: - **Tabla**: contenedor de cadenas, asociado a una familia. La familia `inet` cubre IPv4 e IPv6 a la vez, y es la que usarás. - **Cadena base**: una cadena enganchada a un punto del kernel (`hook`), con prioridad y política. `input` filtra el tráfico que va al servidor, `forward` el que lo atraviesa y `output` el que sale de él. - **Regla**: condiciones y una acción (`accept`, `drop`, `reject`, `jump`...). - **Conjuntos** (`set`) y **mapas**: listas de direcciones, puertos o pares con las que una sola regla sustituye a decenas. Comparación rápida con iptables: | iptables | nftables | |----------|----------| | `iptables` + `ip6tables` por separado | Una tabla `inet` para ambos | | Tablas y cadenas fijas | Tablas y cadenas definidas por ti | | Una regla por IP o puerto | Conjuntos: `tcp dport { 80, 443 }` | | `-m conntrack --ctstate ESTABLISHED` | `ct state established` | | `iptables-save` / `iptables-restore` | `nft list ruleset` / `nft -f archivo` | ## Paso 3: Escribir el ruleset Toda la configuración vivirá en un archivo que se carga de forma atómica: o se aplica entero o no se aplica nada. Haz una copia del archivo de ejemplo y ábrelo: ```bash sudo cp /etc/nftables.conf /etc/nftables.conf.orig sudo nano /etc/nftables.conf ``` Sustituye su contenido por el siguiente: ```text #!/usr/sbin/nft -f flush ruleset define SSH_PORT = 22 define WEB_PORTS = { 80, 443 } table inet filter { # IP con acceso completo (oficina, VPN, monitorización) set trusted4 { type ipv4_addr flags interval elements = { 198.51.100.20 } } # IP bloqueadas manualmente set blocklist4 { type ipv4_addr flags interval } # Contadores dinámicos para limitar conexiones nuevas a SSH por IP set ssh_meter4 { type ipv4_addr flags dynamic timeout 1m } set ssh_meter6 { type ipv6_addr flags dynamic timeout 1m } chain input { type filter hook input priority filter; policy drop; iif "lo" accept ct state established,related accept ct state invalid drop ip saddr @blocklist4 drop ip saddr @trusted4 accept # ICMPv6 es necesario para que IPv6 funcione meta l4proto ipv6-icmp accept icmp type echo-request limit rate 5/second accept tcp dport $SSH_PORT ct state new add @ssh_meter4 { ip saddr limit rate over 10/minute } drop tcp dport $SSH_PORT ct state new add @ssh_meter6 { ip6 saddr limit rate over 10/minute } drop tcp dport $SSH_PORT accept tcp dport $WEB_PORTS accept limit rate 5/minute log prefix "nft-drop: " level warn } chain forward { type filter hook forward priority filter; policy drop; } chain output { type filter hook output priority filter; policy accept; } } ``` Qué hace cada parte: - `flush ruleset` al principio vacía todo antes de cargar, de modo que el archivo describe el estado completo del firewall y recargarlo es idempotente. - `define` crea variables que puedes reutilizar con `$NOMBRE`. - `ct state established,related accept` deja pasar las respuestas a conexiones que el servidor inició. Sin esta regla nada funcionaría con la política `drop`. - `trusted4` y `blocklist4` son conjuntos con `flags interval`, que admiten tanto IP sueltas como rangos (`203.0.113.0/24`). Podrás cambiarlos en caliente sin tocar reglas. - Las reglas de SSH añaden cada IP de origen a un conjunto dinámico con un limitador propio. Si una IP abre más de 10 conexiones nuevas por minuto, las siguientes se descartan. Hay un conjunto por familia porque cada uno guarda un tipo de dirección. - La última regla registra, como máximo 5 veces por minuto, lo que va a descartar la política. Si no tienes una IP de confianza fija, deja el conjunto `trusted4` sin la línea `elements`. ## Paso 4: Validar y aplicar con reversión automática Comprueba la sintaxis sin aplicar nada con `-c`: ```bash sudo nft -c -f /etc/nftables.conf ``` Si no muestra nada, el archivo es válido. Antes de cargarlo, programa una reversión: un temporizador de systemd que vaciará el ruleset (dejando el servidor abierto) dentro de 3 minutos si no lo cancelas. Así, si una regla te deja sin SSH, recuperas el acceso solo: ```bash sudo systemd-run --on-active=3min --unit=nft-rollback /usr/sbin/nft flush ruleset ``` ```output Running timer as unit: nft-rollback.timer Will run service as unit: nft-rollback.service ``` Aplica el ruleset: ```bash sudo nft -f /etc/nftables.conf ``` Abre **una segunda sesión SSH** desde otra terminal. Si puedes entrar, cancela la reversión: ```bash sudo systemctl stop nft-rollback.timer ``` Si no puedes entrar, espera a que pasen los 3 minutos, vuelve a conectar y revisa el archivo. Comprueba el ruleset cargado: ```bash sudo nft list chain inet filter input ``` ```output table inet filter { chain input { type filter hook input priority filter; policy drop; iif "lo" accept ct state established,related accept ct state invalid drop ... ``` ## Paso 5: Cargar el firewall en cada arranque El servicio `nftables` carga `/etc/nftables.conf` al iniciar el sistema, pero en Ubuntu viene desactivado. Habilítalo y arráncalo: ```bash sudo systemctl enable --now nftables ``` Verifica su estado: ```bash systemctl status nftables --no-pager ``` ```output ● nftables.service - nftables Loaded: loaded (/usr/lib/systemd/system/nftables.service; enabled; preset: enabled) Active: active (exited) since Thu 2026-09-24 11:02:17 UTC; 4s ago ``` `active (exited)` es el estado correcto: el servicio carga las reglas y termina. A partir de ahora, para aplicar cambios en el archivo usa `sudo systemctl reload nftables` (o `sudo nft -f /etc/nftables.conf`). ## Paso 6: Gestionar el firewall en caliente Los conjuntos permiten bloquear o permitir IP sin recargar el archivo. Bloquea una IP y un rango: ```bash sudo nft add element inet filter blocklist4 { 192.0.2.77, 203.0.113.0/24 } ``` Consulta el contenido del conjunto: ```bash sudo nft list set inet filter blocklist4 ``` ```output table inet filter { set blocklist4 { type ipv4_addr flags interval elements = { 192.0.2.77, 203.0.113.0/24 } } } ``` Desbloquea una dirección: ```bash sudo nft delete element inet filter blocklist4 { 192.0.2.77 } ``` Mira qué IP están ahora mismo bajo el limitador de SSH: ```bash sudo nft list set inet filter ssh_meter4 ``` Para borrar una regla concreta necesitas su identificador (`handle`). Muéstralos con `-a`: ```bash sudo nft -a list chain inet filter input ``` ```output tcp dport { 80, 443 } accept # handle 14 ``` ```bash sudo nft delete rule inet filter input handle 14 ``` > Nota: los cambios hechos con `nft add` o `nft delete` se pierden al reiniciar o al recargar el servicio, porque `/etc/nftables.conf` empieza con `flush ruleset`. Todo lo que deba ser permanente, escríbelo en el archivo. Para ver cuántos paquetes coinciden con una regla, añade `counter` delante de la acción en el archivo (por ejemplo `tcp dport $WEB_PORTS counter accept`) y consúltalo con `sudo nft list chain inet filter input`. ## Paso 7: Consultar el registro Los paquetes descartados aparecen en el registro del kernel con el prefijo `nft-drop:`: ```bash sudo journalctl -k -g 'nft-drop' -n 20 --no-pager ``` ```output sep 24 11:10:42 server kernel: nft-drop: IN=eth0 OUT= MAC=... SRC=192.0.2.90 DST=203.0.113.10 LEN=44 PROTO=TCP SPT=40112 DPT=3306 ... ``` `DPT` muestra el puerto de destino. Si aparece tráfico legítimo, añade el puerto a las reglas y recarga. ## Paso 8 (opcional): Reenviar un puerto con NAT Si el servidor hace de puerta de enlace para una red privada, por ejemplo una VM en `10.0.0.20`, habilita primero el reenvío en el kernel: ```bash echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-ip-forward.conf sudo sysctl --system ``` Añade al final de `/etc/nftables.conf` una tabla de NAT. Sustituye `eth0` por tu interfaz pública: ```text table ip nat { chain prerouting { type nat hook prerouting priority dstnat; policy accept; iifname "eth0" tcp dport 8080 dnat to 10.0.0.20:80 } chain postrouting { type nat hook postrouting priority srcnat; policy accept; ip saddr 10.0.0.0/24 oifname "eth0" masquerade } } ``` Y permite ese tráfico en la cadena `forward` de la tabla `inet filter`, cambiando su contenido por: ```text chain forward { type filter hook forward priority filter; policy drop; ct state established,related accept ct status dnat accept ip saddr 10.0.0.0/24 oifname "eth0" accept } ``` `ct status dnat accept` deja pasar cualquier conexión que haya sido redirigida por una regla `dnat`, así no tienes que repetir la IP y el puerto. Valida y recarga con `sudo nft -c -f /etc/nftables.conf && sudo systemctl reload nftables`. ## Migrar reglas desde iptables El paquete `iptables` de Ubuntu incluye herramientas para traducir reglas a sintaxis de nftables. Para una regla suelta: ```bash iptables-translate -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT ``` ```output nft 'add rule ip filter INPUT tcp dport 22 ct state new counter accept' ``` Para un archivo completo guardado con `iptables-save`: ```bash sudo iptables-save > iptables.rules iptables-restore-translate -f iptables.rules > translated.nft ``` Usa el resultado como punto de partida, no como configuración final: la traducción es literal (tablas `ip` separadas, cadenas en mayúsculas, sin conjuntos). Lo habitual es reescribirlo en una tabla `inet` como la del paso 3 y, una vez probado, dejar de usar las reglas de iptables. ## Solución de problemas **`Error: Could not process rule: No such file or directory`**: la regla hace referencia a una tabla, cadena o conjunto que no existe o está mal escrito. Revisa los nombres con `sudo nft list ruleset`. **`Error: syntax error, unexpected ...`** al validar: `nft` indica la línea y marca con `^^^` la posición exacta. Los fallos típicos son un `;` que falta tras `policy drop` o llaves sin cerrar. **IPv6 deja de funcionar tras aplicar el firewall**: falta la regla `meta l4proto ipv6-icmp accept`, sin la cual el servidor no puede resolver vecinos ni recibir anuncios del router. **Las reglas no se cargan tras reiniciar**: comprueba `systemctl is-enabled nftables` y que UFW no esté habilitado. Consulta errores con `sudo journalctl -u nftables -b --no-pager`. **Te has quedado sin acceso y no programaste la reversión**: entra por la consola del proveedor y ejecuta `sudo nft flush ruleset`. Corrige el archivo antes de volver a cargarlo. ## Conclusión Has creado un firewall con nftables que cubre IPv4 e IPv6 en una sola tabla, con listas de IP gestionables en caliente, límite de conexiones SSH por IP y registro de lo que se descarta, aplicado con reversión automática y cargado en cada arranque. Mantener todo en `/etc/nftables.conf` hace que el estado del firewall sea fácil de revisar y versionar. Como siguientes pasos puedes: - Integrar Fail2ban con la acción `nftables` para añadir automáticamente al bloqueo las IP que fallan al autenticarse. - Desplegar el mismo `/etc/nftables.conf` en todos tus servidores con Ansible. - Añadir reglas de salida en la cadena `output` si necesitas restringir a qué destinos puede conectar el servidor.