TL;DR — Resumen Rápido
nftables reemplaza iptables en Linux con sintaxis limpia y carga atómica. Guía de migración con sets, NAT, limitación de tasa y firewall web.
nftables es el moderno framework de clasificación de paquetes del kernel de Linux y el reemplazo oficial de la cadena de herramientas legada iptables, ip6tables, arptables y ebtables. Disponible desde el kernel 3.13 y ahora el backend predeterminado en Debian 10+, Ubuntu 20.10+, RHEL 8+ y Fedora 18+, nftables ofrece una interfaz de comandos unificada, coincidencia nativa basada en sets y carga atómica de conjuntos de reglas que elimina las brechas de seguridad inherentes a las actualizaciones regla por regla de iptables. Esta guía cubre el camino completo de migración, desde la instalación de nftables y la comprensión de su jerarquía de objetos hasta la construcción de un firewall de servidor web listo para producción con sets, limitación de tasa, NAT e integración persistente con systemd.
Requisitos Previos
Antes de comenzar, asegúrate de tener:
- Un servidor Linux con kernel 3.13 o posterior (se recomienda Ubuntu 20.04+, Debian 10+ o RHEL 8+)
- Acceso a terminal con privilegios
sudo - Acceso SSH al servidor si configuras de forma remota — mantén una segunda sesión abierta como red de seguridad
- Familiaridad con puertos TCP/UDP y redes IP básicas
- Reglas de iptables exportadas si planeas migrarlas (
sudo iptables-save > ~/iptables-backup.txt)
Por Qué nftables Reemplaza a iptables
La cadena de herramientas legada de Netfilter evolucionó orgánicamente durante dos décadas, resultando en cuatro utilidades separadas (iptables, ip6tables, arptables, ebtables) cada una con su propia sintaxis, interfaz de kernel y mecanismo de extensión. nftables fue diseñado desde cero para resolver estos problemas estructurales.
Framework Unificado
Un solo comando nft reemplaza a las cuatro herramientas legadas. Una única tabla de familia inet maneja tanto IPv4 como IPv6 de forma simultánea, eliminando la necesidad de duplicar cada regla para ambas familias de direcciones.
Mejor Sintaxis
nftables usa una gramática estructurada que se lee de forma más natural que las banderas de iptables:
# iptables
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
# Equivalente en nftables
nft add rule inet filter input tcp dport 443 ct state new accept
Carga Atómica de Reglas
Con iptables, agregar y eliminar reglas ocurre una a la vez — existe una condición de carrera entre cada operación individual. nftables carga un conjunto de reglas completo como una única transacción atómica usando nft -f, asegurando que el firewall nunca esté en un estado parcial.
Sets y Mapas Nativos
iptables requiere la extensión separada ipset para hacer coincidir eficientemente grandes listas de IPs o puertos. nftables incluye sets y mapas de forma nativa, admitiendo tiempos de espera, claves concatenadas y mapas de veredictos sin paquetes adicionales.
Fundamentos del Comando nft
nftables organiza todo en una jerarquía de tres niveles: las tablas contienen cadenas, las cadenas contienen reglas. Cada tabla pertenece a una familia de direcciones.
Familias de Direcciones
| Familia | Tráfico gestionado |
|---|---|
ip | Solo IPv4 |
ip6 | Solo IPv6 |
inet | Tanto IPv4 como IPv6 (recomendado para servidores) |
arp | Protocolo ARP |
bridge | Nivel de puente/switch |
netdev | Ingreso en una interfaz específica |
Gestión de Tablas
sudo nft add table inet filter # crear una tabla
sudo nft list tables # listar todas las tablas
sudo nft delete table inet filter # eliminar tabla y contenido
sudo nft flush table inet filter # eliminar todas las reglas, conservar estructura
Gestión de Cadenas
Las cadenas base están vinculadas a un gancho de Netfilter. Requieren un type, hook y priority:
sudo nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
sudo nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
sudo nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
Gestión de Reglas
sudo nft add rule inet filter input tcp dport 22 accept # agregar al final
sudo nft insert rule inet filter input tcp dport 22 accept # insertar al inicio
sudo nft list chain inet filter input # ver con identificadores
sudo nft delete rule inet filter input handle 5 # eliminar por identificador
Construyendo un Firewall Básico
La siguiente secuencia construye un firewall de referencia completo paso a paso.
Paso 1 — Crear la Tabla y las Cadenas
sudo nft add table inet filter
sudo nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
sudo nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
sudo nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
Paso 2 — Aceptar Conexiones Establecidas y Loopback
Estas reglas deben ir primero para que las sesiones existentes no se interrumpan:
sudo nft add rule inet filter input ct state established,related accept
sudo nft add rule inet filter input ct state invalid drop
sudo nft add rule inet filter input iif lo accept
Paso 3 — Permitir ICMP
sudo nft add rule inet filter input ip protocol icmp limit rate 10/second burst 20 packets accept
sudo nft add rule inet filter input ip6 nexthdr icmpv6 limit rate 10/second burst 20 packets accept
Paso 4 — Permitir Puertos de Servicios
sudo nft add rule inet filter input tcp dport 22 accept
sudo nft add rule inet filter input tcp dport { 80, 443 } accept
Paso 5 — Rechazo Final
Envía un error ICMP al tráfico no coincidente en lugar de descartarlo silenciosamente:
sudo nft add rule inet filter input reject with icmpx type port-unreachable
Sets y Mapas para Gestión Eficiente de Reglas
Los sets eliminan la necesidad de escribir una regla por puerto o dirección IP. Pueden actualizarse dinámicamente sin modificar las reglas que los referencian.
Sets Anónimos (En Línea)
sudo nft add rule inet filter input tcp dport { 22, 80, 443, 8443 } accept
Sets con Nombre
sudo nft add set inet filter tcp_accepted { type inet_service \; }
sudo nft add element inet filter tcp_accepted { 22, 80, 443 }
sudo nft add rule inet filter input tcp dport @tcp_accepted accept
# Agregar o eliminar puertos sin tocar la regla
sudo nft add element inet filter tcp_accepted { 8080 }
sudo nft delete element inet filter tcp_accepted { 8080 }
Lista de Bloqueo de IPs con Expiración Automática
sudo nft add set inet filter blocklist { type ipv4_addr \; timeout 24h \; }
sudo nft add element inet filter blocklist { 203.0.113.10, 198.51.100.5 }
sudo nft add rule inet filter input ip saddr @blocklist drop
Sets Concatenados (Coincidencia Multi-campo)
sudo nft add set inet filter db_access { type ipv4_addr . inet_service \; }
sudo nft add element inet filter db_access { 10.0.1.20 . 3306, 10.0.1.21 . 5432 }
sudo nft add rule inet filter input ip saddr . tcp dport @db_access accept
Limitación de Tasa y Seguimiento de Conexiones
Limitación Global de SSH
sudo nft add rule inet filter input tcp dport 22 ct state new limit rate 5/minute burst 10 packets accept
sudo nft add rule inet filter input tcp dport 22 ct state new drop
Limitación de Tasa por IP de Origen con Contadores
Los contadores imponen límites de forma independiente para cada dirección de origen:
sudo nft add rule inet filter input tcp dport 22 ct state new \
meter ssh_limit { ip saddr limit rate 3/minute burst 5 packets } accept
Estados de Seguimiento de Conexiones
| Estado | Significado |
|---|---|
new | Primer paquete de una nueva conexión |
established | Tráfico de retorno para una conexión aceptada |
related | Asociado con una conexión existente |
invalid | No se puede identificar — siempre descartar |
untracked | Omite explícitamente el conntrack |
NAT y Reenvío de Puertos
Crear la Tabla NAT
sudo nft add table inet nat
sudo nft add chain inet nat prerouting { type nat hook prerouting priority -100 \; }
sudo nft add chain inet nat postrouting { type nat hook postrouting priority 100 \; }
Masquerade (NAT de Origen para Routers/VPNs)
sudo nft add rule inet nat postrouting oif "eth0" masquerade
Reenvío de Puertos (NAT de Destino)
sudo nft add rule inet nat prerouting iif "eth0" tcp dport 8080 dnat to 10.0.0.50:80
sudo nft add rule inet filter forward ip daddr 10.0.0.50 tcp dport 80 ct state new accept
sudo nft add rule inet filter forward ct state established,related accept
Habilitar el reenvío IP:
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-nftables.conf
sudo sysctl -p /etc/sysctl.d/99-nftables.conf
Registro y Monitoreo
sudo nft add rule inet filter input ct state invalid log prefix "nft_invalid: " level warn drop
sudo journalctl -k --grep="nft_" -f
sudo nft monitor
Guardar y Restaurar Conjuntos de Reglas
sudo nft list ruleset | sudo tee /etc/nftables.conf
sudo nft -c -f /etc/nftables.conf # prueba de sintaxis en seco
sudo nft -f /etc/nftables.conf # aplicar atómicamente
Migración desde iptables
Traducir Reglas Individuales
iptables-translate -A INPUT -p tcp --dport 443 -j ACCEPT
# Salida: nft add rule ip filter INPUT tcp dport 443 counter accept
Traducir un Conjunto de Reglas Completo
sudo iptables-save > /tmp/ipt-backup.txt
iptables-restore-translate -f /tmp/ipt-backup.txt > /tmp/nft-migrated.nft
sudo nft -f /tmp/nft-migrated.nft
Mejores Prácticas de Migración
- Haz una copia de seguridad primero —
sudo iptables-save > ~/iptables-backup.txt - Traduce y revisa — nunca apliques reglas auto-traducidas sin revisión
- Prueba en no producción — aplica las reglas traducidas en un servidor de prueba primero
- Mantén una sesión de consola — acceso a consola de nube o KVM como respaldo
- Vacía iptables después de confirmar —
sudo iptables -F && sudo iptables -X - Deshabilita el servicio legado —
sudo systemctl disable iptables
Integración con systemd
sudo systemctl enable nftables
sudo systemctl start nftables
sudo systemctl reload nftables # recarga atómica del conjunto de reglas
Comparación: nftables vs iptables vs UFW vs firewalld
| Característica | nftables | iptables | UFW | firewalld |
|---|---|---|---|---|
| Herramienta única para todo | Sí | No (4 herramientas) | Sí (frontend) | Sí (frontend) |
| IPv4 + IPv6 en una tabla | Sí (inet) | No | Sí | Sí |
| Sets/mapas nativos | Sí | No (necesita ipset) | No | No |
| Reemplazo atómico de reglas | Sí (nft -f) | No | No | Parcial |
| Interfaz simplificada | No | No | Sí | Sí |
| Flexibilidad de scripting | Alta | Media | Baja | Media |
| Rendimiento a escala | Excelente | Bueno | Bueno | Bueno |
Escenario Real: Servidor Web y Proxy Inverso
Tienes un servidor de producción con Nginx como proxy inverso frente a dos servidores de aplicación en 10.0.0.10 y 10.0.0.11, con una interfaz pública (eth0) y una interna (eth1). Requisitos: acceso SSH solo desde tu CIDR de gestión, HTTP/HTTPS público, tráfico de backend solo desde la red interna y protección contra fuerza bruta SSH.
#!/usr/sbin/nft -f
flush ruleset
define WAN = eth0
define LAN = eth1
define MGMT_CIDR = 10.10.10.0/24
table inet filter {
set mgmt_hosts {
type ipv4_addr
flags interval
elements = { $MGMT_CIDR }
}
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
ct state invalid drop
iif lo accept
ip protocol icmp limit rate 10/second burst 20 packets accept
ip saddr @mgmt_hosts tcp dport 22 ct state new \
meter ssh_mgmt { ip saddr limit rate 5/minute burst 10 packets } accept
tcp dport { 80, 443 } accept
reject with icmpx type port-unreachable
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state established,related accept
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Errores Comunes y Casos Límite
- El orden de las reglas importa — nftables evalúa las reglas de arriba hacia abajo. Coloca
ct state established,related acceptantes de cualquier regla de descarte. - Sin tablas ni cadenas por defecto — nftables comienza vacío. Si olvidas crear una cadena, el tráfico no se filtra en absoluto.
- flush ruleset es destructivo — inclúyelo siempre al principio de los archivos de configuración, pero nunca lo ejecutes de forma interactiva en un servidor en producción sin un plan de respaldo.
- Las variables requieren
define— nftables usadefine VAR = valueen los archivos de configuración; no puedes usar variables de shell directamente en los comandosnft. - iptables y nftables pueden entrar en conflicto — si ambos están ejecutándose, las reglas de ambos frameworks se aplican de forma independiente.
Resolución de Problemas
Las reglas no persisten tras reinicio: Verifica que el servicio esté habilitado con sudo systemctl is-enabled nftables. Comprueba que /etc/nftables.conf contenga flush ruleset al inicio y tenga sintaxis nft válida.
SSH bloqueado tras aplicar reglas: Accede mediante consola de nube, luego ejecuta sudo nft flush ruleset. Reconstruye la configuración con SSH permitido antes de establecer una política de descarte.
Módulo de kernel faltante: Ejecuta lsmod | grep nf_tables. Si está ausente, cárgalo con sudo modprobe nf_tables nft_chain_nat nft_ct.
Error de sintaxis en archivo de configuración: Usa sudo nft -c -f /etc/nftables.conf para una prueba en seco que reporta la línea y el error exactos sin aplicar cambios.
Resumen
nftables es el reemplazo listo para producción de iptables en cualquier sistema Linux con kernel 3.13 o posterior. Su comando nft unificado, sets y mapas nativos, carga atómica de reglas y sintaxis más limpia abordan cada debilidad estructural principal de la cadena de herramientas legada.
Puntos clave:
- Usa la familia de direcciones
inetpara gestionar tanto IPv4 como IPv6 desde una sola tabla - Siempre comienza con
ct state established,related accepteiif lo accept - Usa sets con nombre para gestionar listas de puertos e IPs sin reescribir reglas
- Protege los servicios de autenticación con contadores por IP en lugar de límites de tasa globales
- Almacena el conjunto de reglas en
/etc/nftables.confy cárgalo atómicamente connft -f - Habilita el servicio systemd de nftables para que el conjunto de reglas persista tras reinicios
- Usa
iptables-restore-translatepara convertir conjuntos de reglas existentes y revísalos cuidadosamente antes de aplicar