Inicio Linux & Systems Networks & Infrastructure Cybersecurity Cloud & DevOps SIEM & Monitoring DFIR & Threat Intel Development & Other Todas las categorias Herramientas

Guía práctica de iptables y nftables en 2026

Guía práctica de iptables y nftables en 2026

Tabla de contenidos

En 2026, el ecosistema de filtrado de paquetes en Linux vive una transición que lleva años en marcha pero que muchos equipos siguen aplazando: el paso de iptables a nftables. Distribuciones como Debian 10+, RHEL 8+, Ubuntu 20.04+ y Arch Linux ya usan nftables como backend por defecto. Sin embargo, iptables sigue presente en miles de servidores en producción, scripts de despliegue y documentación que nadie se atreve a tocar.

Esta guía no elige bando: aprenderás ambas herramientas, entenderás cuándo usar cada una y sabrás cómo migrar cuando llegue el momento. Si administras servidores Linux o trabajas en seguridad de red, aquí tienes la referencia práctica que necesitas tener a mano.

Conceptos fundamentales

Tanto iptables como nftables son interfaces de usuario para Netfilter, el framework de filtrado de paquetes integrado en el kernel de Linux. Netfilter opera en varios puntos del recorrido de un paquete (hooks): PREROUTING, INPUT, FORWARD, OUTPUT y POSTROUTING.

Tablas y cadenas

Las reglas se organizan en tablas según su función:

  • filter — La tabla por defecto. Contiene las cadenas INPUT, FORWARD y OUTPUT para decidir si un paquete se acepta o se descarta.
  • nat — Para traducción de direcciones (PREROUTING, OUTPUT, POSTROUTING).
  • mangle — Para modificar cabeceras de paquetes.
  • raw — Para control de seguimiento de conexiones (conntrack).

Cada tabla contiene cadenas (chains), que son listas ordenadas de reglas. Cuando un paquete atraviesa una cadena, se evalúan las reglas en orden hasta que una coincide. Si ninguna coincide, se aplica la política por defecto de la cadena.

Una regla tiene dos partes: los criterios de coincidencia (match) y el objetivo (target). Los targets más comunes son ACCEPT, DROP, REJECT, LOG y RETURN.


iptables: Guía de referencia rápida

Limpiar y resetear reglas

El primer paso antes de configurar un firewall limpio es eliminar todas las reglas existentes:

BASH
bash
# Eliminar todas las reglas de la tabla filter
iptables --flush
iptables --delete-chain

# Eliminar todas las reglas de NAT y mangle
iptables --table nat --flush
iptables --table mangle --flush

# Resetear contadores de paquetes y bytes
iptables --zero

Políticas por defecto

La política por defecto determina qué ocurre cuando ninguna regla coincide. La estrategia más segura es denegar todo por defecto y luego permitir solo lo necesario:

BASH
bash
# Política restrictiva (recomendada para servidores)
iptables --policy INPUT DROP
iptables --policy FORWARD DROP
iptables --policy OUTPUT ACCEPT

# Política permisiva (útil durante desarrollo)
iptables --policy INPUT ACCEPT
iptables --policy FORWARD ACCEPT
iptables --policy OUTPUT ACCEPT

Ver las reglas activas

BASH
bash
# Listar reglas con números de línea
iptables --list --line-numbers

# Verbose: muestra interfaz, contadores de paquetes/bytes y opciones
iptables --list --verbose --numeric --line-numbers

# Ver solo la tabla nat
iptables --table nat --list --verbose --numeric --line-numbers

Eliminar reglas

BASH
bash
# Eliminar por número de línea (ver con --line-numbers primero)
iptables --delete INPUT 3

# Eliminar por coincidencia exacta con la regla
iptables --delete INPUT --protocol tcp --dport 8080 --jump ACCEPT

Guardar y restaurar reglas

Las reglas de iptables no persisten tras un reinicio. Para hacerlas permanentes:

BASH
bash
# Guardar reglas actuales
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6

# Restaurar reglas desde archivo
iptables-restore < /etc/iptables/rules.v4

En sistemas con systemd, instala el paquete iptables-persistent (Debian/Ubuntu) o habilita el servicio iptables (RHEL/CentOS) para que las reglas se carguen automáticamente al arranque.

Reglas habituales

BASH
bash
# Permitir loopback (imprescindible)
iptables --append INPUT --in-interface lo --jump ACCEPT
iptables --append OUTPUT --out-interface lo --jump ACCEPT

# Permitir conexiones ya establecidas y relacionadas
iptables --append INPUT --match conntrack --ctstate ESTABLISHED,RELATED --jump ACCEPT

# Descartar paquetes con estado INVALID
iptables --append INPUT --match conntrack --ctstate INVALID --jump DROP

# SSH (puerto 22)
iptables --append INPUT --protocol tcp --dport 22 --match conntrack --ctstate NEW,ESTABLISHED --jump ACCEPT

# HTTP y HTTPS
iptables --append INPUT --protocol tcp --match multiport --dports 80,443 --jump ACCEPT

# DNS (si el servidor actúa como resolver)
iptables --append INPUT --protocol udp --dport 53 --jump ACCEPT
iptables --append INPUT --protocol tcp --dport 53 --jump ACCEPT

# ICMP (ping) -- permite diagnóstico de red
iptables --append INPUT --protocol icmp --icmp-type echo-request --jump ACCEPT

Bloquear tráfico por IP, rango y puerto

BASH
bash
# Bloquear una IP concreta
iptables --append INPUT --source 203.0.113.42 --jump DROP

# Bloquear un rango CIDR
iptables --append INPUT --source 198.51.100.0/24 --jump DROP

# Bloquear rango de puertos
iptables --append INPUT --protocol tcp --dport 8000:8100 --jump DROP

# Bloquear una IP de origen en un puerto específico
iptables --append INPUT --source 203.0.113.42 --protocol tcp --dport 80 --jump DROP

Limitación de tasa (prevención de DoS)

BASH
bash
# Limitar nuevas conexiones SSH a 3 por minuto por IP
iptables --append INPUT --protocol tcp --dport 22 \
  --match conntrack --ctstate NEW \
  --match recent --set --name SSH --rsource

iptables --append INPUT --protocol tcp --dport 22 \
  --match conntrack --ctstate NEW \
  --match recent --update --seconds 60 --hitcount 4 --name SSH --rsource \
  --jump DROP

# Limitar SYN floods usando hashlimit
iptables --append INPUT --protocol tcp --syn \
  --match hashlimit \
  --hashlimit-name syn_flood \
  --hashlimit-above 200/second \
  --hashlimit-burst 1000 \
  --hashlimit-mode srcip \
  --jump DROP

NAT y reenvío de puertos

BASH
bash
# Habilitar IP forwarding (obligatorio para NAT)
echo 1 > /proc/sys/net/ipv4/ip_forward
# O de forma permanente en /etc/sysctl.conf:
# net.ipv4.ip_forward = 1

# MASQUERADE -- NAT de salida para una interfaz (p.ej. router con IP dinámica)
iptables --table nat --append POSTROUTING --out-interface eth0 --jump MASQUERADE

# SNAT -- NAT de salida con IP estática (más eficiente que MASQUERADE)
iptables --table nat --append POSTROUTING --source 192.168.1.0/24 \
  --out-interface eth0 --jump SNAT --to-source 203.0.113.10

# DNAT -- Reenvío de puerto 80 externo a servidor interno en 8080
iptables --table nat --append PREROUTING \
  --in-interface eth0 --protocol tcp --dport 80 \
  --jump DNAT --to-destination 192.168.1.100:8080

# Permitir el tráfico redirigido en FORWARD
iptables --append FORWARD --destination 192.168.1.100 --protocol tcp \
  --dport 8080 --jump ACCEPT

Logging

BASH
bash
# Registrar paquetes descartados (insertar ANTES de la regla DROP)
iptables --append INPUT --match limit --limit 5/min --jump LOG \
  --log-prefix "iptables-DROP: " --log-level 4

# Registrar intentos de conexión a puertos no permitidos
iptables --append INPUT --protocol tcp --dport 23 --jump LOG \
  --log-prefix "TELNET-BLOCKED: " --log-level warning

# Los logs aparecen en /var/log/kern.log o con: journalctl -k | grep iptables

nftables: La evolución del filtrado en Linux

Por qué nftables en 2026

nftables no es simplemente "iptables con mejor sintaxis". Aporta mejoras estructurales importantes:

  • Framework unificado: reemplaza iptables, ip6tables, arptables y ebtables con una sola herramienta.
  • Operaciones atómicas: puedes cargar un conjunto completo de reglas en una sola operación, sin ventanas de tiempo sin protección.
  • Sets y mapas: estructuras de datos nativas para gestionar listas de IPs, puertos o rangos de forma eficiente.
  • Mejor rendimiento: el bytecode generado es más eficiente que el modelo de evaluación lineal de iptables.
  • Sintaxis legible: las reglas son más compactas y fáciles de auditar.

Sintaxis básica

La jerarquía en nftables es: familia → tabla → cadena → regla. Las familias más comunes son ip (IPv4), ip6 (IPv6), inet (ambos), arp y bridge.

BASH
text
# Crear una tabla
nft add table inet filter

# Crear una cadena con política por defecto DROP
nft add chain inet filter input \
  '{ type filter hook input priority 0 ; policy drop ; }'

# Crear la cadena OUTPUT con política ACCEPT
nft add chain inet filter output \
  '{ type filter hook output priority 0 ; policy accept ; }'

# Añadir una regla (permite SSH)
nft add rule inet filter input tcp dport 22 ct state new,established accept

# Listar todo el ruleset
nft list ruleset

# Listar una tabla concreta
nft list table inet filter

Equivalencias con iptables

Las reglas más comunes tienen su equivalente directo en nftables, con una sintaxis más natural:

BASH
text
# Loopback
nft add rule inet filter input iif lo accept
nft add rule inet filter output oif lo accept

# Conexiones establecidas y relacionadas
nft add rule inet filter input ct state established,related accept

# Descartar paquetes INVALID
nft add rule inet filter input ct state invalid drop

# SSH, HTTP y HTTPS en una sola regla
nft add rule inet filter input tcp dport { 22, 80, 443 } accept

# DNS
nft add rule inet filter input udp dport 53 accept
nft add rule inet filter input tcp dport 53 accept

# ICMP (ping)
nft add rule inet filter input icmp type echo-request accept
nft add rule inet filter input icmpv6 type echo-request accept

# Bloquear una IP
nft add rule inet filter input ip saddr 203.0.113.42 drop

# Bloquear un rango CIDR
nft add rule inet filter input ip saddr 198.51.100.0/24 drop

# Rango de puertos
nft add rule inet filter input tcp dport 8000-8100 drop

NAT con nftables

BASH
text
# Crear tabla NAT
nft add table ip nat

# Cadenas de pre y postrouting
nft add chain ip nat prerouting \
  '{ type nat hook prerouting priority -100 ; }'
nft add chain ip nat postrouting \
  '{ type nat hook postrouting priority 100 ; }'

# MASQUERADE
nft add rule ip nat postrouting oif eth0 masquerade

# SNAT con IP estática
nft add rule ip nat postrouting ip saddr 192.168.1.0/24 oif eth0 \
  snat to 203.0.113.10

# DNAT -- reenvío de puerto 80 a servidor interno
nft add rule ip nat prerouting iif eth0 tcp dport 80 \
  dnat to 192.168.1.100:8080

Limitación de tasa en nftables

BASH
text
# Limitar nuevas conexiones SSH a 3 por minuto por IP de origen
nft add rule inet filter input tcp dport 22 ct state new \
  meter ssh_limit { ip saddr limit rate 3/minute } accept

# Descartar lo que supere el límite
nft add rule inet filter input tcp dport 22 ct state new drop

# Limitar ICMP para prevenir ping flood
nft add rule inet filter input icmp type echo-request \
  limit rate 10/second burst 20 packets accept

Logging en nftables

BASH
text
# Registrar y luego descartar (dos reglas consecutivas)
nft add rule inet filter input limit rate 5/minute \
  log prefix "nft-DROP: " level warn
nft add rule inet filter input drop

# Logging solo de TCP sin establecer en puertos críticos
nft add rule inet filter input tcp dport 23 \
  log prefix "TELNET-BLOCKED: " level warn drop

Sets y mapas: el superpoder de nftables

Los sets son listas de elementos (IPs, puertos, rangos) que se pueden referenciar en múltiples reglas. Son mucho más eficientes que añadir una regla por cada elemento:

BASH
text
# Crear un set de IPs bloqueadas
nft add set inet filter blocklist \
  '{ type ipv4_addr ; flags interval ; }'

# Añadir elementos al set
nft add element inet filter blocklist \
  { 203.0.113.0/24, 198.51.100.42, 192.0.2.0/28 }

# Usar el set en una regla
nft add rule inet filter input ip saddr @blocklist drop

# Añadir o eliminar elementos en caliente (sin recargar el firewall)
nft add element inet filter blocklist { 10.0.0.99 }
nft delete element inet filter blocklist { 10.0.0.99 }

# Set con timeout automático (ideal para bloqueos temporales)
nft add set inet filter temp_block \
  '{ type ipv4_addr ; flags dynamic,timeout ; timeout 1h ; }'

Los mapas (maps) permiten hacer asociaciones clave-valor, útiles para DNAT dinámico o asignación de marcas por IP:

BASH
text
# Mapa de DNAT: puerto de destino -> servidor interno
nft add map ip nat portmap \
  '{ type inet_service : ipv4_addr . inet_service ; }'

nft add element ip nat portmap \
  { 80 : 192.168.1.10 . 8080, 443 : 192.168.1.10 . 8443 }

nft add rule ip nat prerouting iif eth0 \
  dnat to tcp dport map @portmap

Eliminar reglas y gestionar el ruleset

BASH
text
# Ver handles (identificadores) de las reglas
nft --handle list chain inet filter input

# Eliminar una regla por su handle
nft delete rule inet filter input handle 7

# Vaciar una cadena
nft flush chain inet filter input

# Eliminar una tabla completa
nft delete table inet filter

# Limpiar todo el ruleset
nft flush ruleset

Persistencia en nftables

BASH
bash
# Volcar el ruleset completo a un archivo
nft list ruleset > /etc/nftables.conf

# Cargar el ruleset desde archivo (operación atómica)
nft --file /etc/nftables.conf

# Validar sintaxis sin aplicar los cambios
nft --check --file /etc/nftables.conf

# Habilitar el servicio de nftables en systemd
systemctl enable nftables
systemctl start nftables

Migración de iptables a nftables

iptables-translate

La herramienta iptables-translate convierte reglas de iptables al equivalente nftables. Es la forma más rápida de migrar reglas existentes:

BASH
bash
# Traducir una regla individual
iptables-translate --append INPUT --protocol tcp --dport 22 --jump ACCEPT
# Salida: nft add rule ip filter INPUT tcp dport 22 counter accept

# Traducir todas las reglas guardadas
iptables-save | iptables-restore-translate > /etc/nftables.conf

# Revisar el archivo generado antes de aplicarlo
nft --check --file /etc/nftables.conf

# Aplicar si todo es correcto
nft --file /etc/nftables.conf

Capa de compatibilidad iptables-nft

En RHEL 8+ y distribuciones modernas, los comandos iptables, ip6tables, arptables y ebtables son en realidad wrappers que escriben reglas en el backend nftables. Puedes verificarlo:

BASH
sql
# Comprobar qué iptables está en uso
update-alternatives --list iptables

# Cambiar entre el legado y la versión nft
update-alternatives --set iptables /usr/sbin/iptables-nft
update-alternatives --set iptables /usr/sbin/iptables-legacy

# Las reglas escritas con iptables-nft son visibles desde nft
iptables-nft --append INPUT --protocol tcp --dport 80 --jump ACCEPT
nft list ruleset  # aparecerán en la tabla ip iptables

Ejemplo práctico de migración

BASH
bash
# Paso 1: Exportar reglas iptables actuales
iptables-save > /tmp/iptables-backup.rules

# Paso 2: Traducir a sintaxis nftables
iptables-restore-translate --file /tmp/iptables-backup.rules \
  > /tmp/nftables-migrated.conf

# Paso 3: Revisar y limpiar el archivo generado
# (eliminar reglas redundantes, mejorar con sets, etc.)

# Paso 4: Validar sin aplicar
nft --check --file /tmp/nftables-migrated.conf

# Paso 5: Hacer backup del ruleset nftables actual
nft list ruleset > /etc/nftables.conf.bak

# Paso 6: Aplicar las nuevas reglas
nft flush ruleset
nft --file /tmp/nftables-migrated.conf

# Paso 7: Verificar conectividad y guardar permanentemente
nft list ruleset > /etc/nftables.conf

Ejemplo completo: Firewall de servidor web

El siguiente archivo /etc/nftables.conf implementa un firewall completo para un servidor web con SSH, HTTP/HTTPS, rate limiting y logging. Se carga de forma atómica con nft -f:

BASH
bash
#!/usr/sbin/nft -f
# /etc/nftables.conf -- Firewall para servidor web
# Cargar: nft -f /etc/nftables.conf
# Validar: nft --check -f /etc/nftables.conf

flush ruleset

# -------------------------------------------------------
# Tabla principal (inet = IPv4 + IPv6)
# -------------------------------------------------------
table inet filter {

  # Set de IPs bloqueadas -- añadir elementos en caliente
  set blocklist {
    type ipv4_addr
    flags interval
    # elementos: { 203.0.113.0/24, 198.51.100.42 }
  }

  # Set de IPs de administración (solo estas pueden entrar por SSH)
  set admin_ips {
    type ipv4_addr
    flags interval
    elements = { 192.0.2.10, 10.0.0.0/8 }
  }

  chain input {
    type filter hook input priority 0
    policy drop

    # Loopback -- siempre permitir
    iif lo accept comment "Permitir loopback"

    # Conexiones ya establecidas
    ct state established,related accept comment "Permitir conexiones establecidas"

    # Paquetes inválidos -- descartar antes de procesar
    ct state invalid drop comment "Descartar paquetes inválidos"

    # Bloquear IPs de la lista negra
    ip saddr @blocklist drop comment "Bloquear IPs en blocklist"

    # ICMP (ping) con límite de tasa
    icmp type echo-request limit rate 10/second burst 20 packets accept
    icmpv6 type echo-request limit rate 10/second burst 20 packets accept

    # SSH -- solo desde IPs de administración, con rate limiting
    ip saddr @admin_ips tcp dport 22 ct state new \
      meter ssh_rate { ip saddr limit rate 5/minute } \
      accept comment "SSH para administradores"

    ip saddr @admin_ips tcp dport 22 ct state new \
      log prefix "SSH-RATE-LIMIT: " level warn drop

    # HTTP y HTTPS -- acceso público
    tcp dport { 80, 443 } ct state new \
      meter http_rate { ip saddr limit rate 100/second burst 200 } \
      accept comment "HTTP/HTTPS público"

    tcp dport { 80, 443 } ct state new \
      log prefix "HTTP-RATE-LIMIT: " level warn drop

    # Registrar y descartar todo lo demás
    limit rate 5/minute log prefix "nft-INPUT-DROP: " level warn
    drop
  }

  chain forward {
    type filter hook forward priority 0
    policy drop
    comment "Servidor independiente: no reenviar paquetes"
  }

  chain output {
    type filter hook output priority 0
    policy accept
    comment "Tráfico de salida: permitir todo"
  }
}

Para aplicar este firewall y habilitarlo en el arranque:

BASH
bash
# Validar la sintaxis sin aplicar
nft --check --file /etc/nftables.conf

# Aplicar (operación atómica -- si falla, no se aplica nada)
nft --file /etc/nftables.conf

# Verificar que las reglas están activas
nft list ruleset

# Habilitar para el arranque
systemctl enable --now nftables

Buenas prácticas en 2026

Usa nftables para nuevos despliegues

Si estás configurando un servidor desde cero hoy, usa nftables directamente. iptables sigue funcionando, pero su desarrollo está congelado. El mantenimiento activo, las nuevas características y la integración con herramientas modernas (como firewalld o systemd-networkd) están en nftables.

Carga atómica de reglas

Nunca apliques reglas una por una con nft add rule en un entorno de producción. Siempre usa nft --file con un archivo que incluya flush ruleset al inicio. Esto garantiza que la transición entre el estado anterior y el nuevo sea instantánea, sin ventanas de tiempo vulnerables ni reglas inconsistentes.

Usa sets para listas de IPs y puertos

Una regla que referencia un set de 1000 IPs es mucho más eficiente que 1000 reglas individuales. El kernel evalúa los sets con estructuras de datos optimizadas (árboles de intervalos, tablas hash), no con búsqueda lineal. Además, puedes modificar el contenido de un set en caliente sin recargar el firewall:

BASH
text
# Bloquear una IP temporalmente sin recargar el firewall
nft add element inet filter blocklist { 203.0.113.99 }

# Desbloquear
nft delete element inet filter blocklist { 203.0.113.99 }

Registra antes de descartar (log before drop)

Añade siempre una regla de logging justo antes de los drops finales, aunque sea con rate limiting para no saturar el log. Sin logging, diagnosticar por qué un servicio no es accesible se convierte en un ejercicio de adivinación. El prefijo del log (log prefix "...") es clave para filtrar eventos en journalctl:

BASH
text
# Filtrar logs del firewall
journalctl -k --grep "nft-INPUT-DROP"

# En tiempo real
journalctl -kf | grep "nft-"

Documenta tus reglas con comentarios

nftables soporta comentarios inline con comment "...". Úsalos. Una regla sin comentario que bloquea tráfico sin explicación es un problema de mantenimiento esperando su momento:

BASH
bash
tcp dport 8443 accept comment "API interna -- ver ticket INFRA-2847"
ip saddr 192.0.2.0/24 drop comment "Bloqueo ISP abusivo -- revisar en Q3 2026"

Valida siempre con --check antes de aplicar

El flag --check (o -c) parsea y valida el archivo de configuración sin aplicar ningún cambio al kernel. Es gratuito y puede salvarte de un lockout por una errata:

BASH
php
nft --check --file /etc/nftables.conf && echo "OK" || echo "ERROR en la configuracion"

Gestiona el firewall bajo control de versiones

El archivo /etc/nftables.conf debe estar en un repositorio Git. Cada cambio en el firewall es un commit con mensaje descriptivo. Si trabajas con Ansible, Puppet o Salt, gestiona las reglas como código (Infrastructure as Code). Un cambio de firewall sin auditoría es un riesgo de seguridad y un problema operacional.

Haz un rollback automático al cambiar reglas en remoto

Al modificar reglas en un servidor remoto, programa siempre un rollback automático por si te quedas sin acceso:

BASH
php
# Programar rollback en 5 minutos si no se cancela
nft list ruleset > /tmp/nft-backup.conf
(sleep 300 && nft --file /tmp/nft-backup.conf && \
  echo "ROLLBACK ejecutado automaticamente") &
ROLLBACK_PID=$!

# Aplicar nuevas reglas
nft --file /etc/nftables-new.conf

# Si todo funciona, cancelar el rollback
kill $ROLLBACK_PID && echo "Rollback cancelado -- reglas aplicadas correctamente"

La distancia entre un firewall bien configurado y un servidor inaccesible es una sola regla mal escrita. La diferencia entre un sysadmin experimentado y uno que aprende a las malas es tener el rollback preparado antes de tocar nada.

:wq!

Comentarios