UFW vs firewalld: cuál usar según tu distribución Linux 2026
Si te toca configurar un firewall en Linux, la pregunta que aparece antes que cualquier otra es: ¿UFW o firewalld? La respuesta corta: usa el que viene por defecto en tu distro. La respuesta larga — qué hace cada uno, cuándo conviene uno sobre el otro, y cómo migrar sin romper reglas existentes — la cubrimos en esta guía.
UFW en Ubuntu, firewalld en RHEL/CentOS, nftables en el fondo de ambos, iptables legacy que muchos sysadmins todavía configuran a mano. La elección de firewall en Linux no es técnica pura — es también una decisión sobre el “set de defaults” de tu distro. Esta guía documenta las diferencias reales entre UFW, firewalld, nftables pelado e iptables, con benchmarks de performance, casos donde uno es claramente mejor, y los gotchas cuando tienes que interoperar entre distros en un cluster mixto.
Si administras servidores mixtos (Debian + RHEL) o estás eligiendo tu firewall por primera vez, esta guía te lleva a la respuesta.
TL;DR — Lo que vas a tener al final
- Tiempo de lectura: 15-20 minutos.
- Requisitos: Ninguno, es una guía de decisión.
- Resultado: Saber cuál usar según tu distro y caso de uso.
- Troubleshooting típico: reglas que se pierden al reboot, conflictos entre UFW y Docker. Solución: `nft list ruleset` y revisar iptables-persistent.
Índice
- [Qué son y por qué existen dos](#qué-son-y-por-qué-existen-dos)
- [Cuándo usar UFW (Ubuntu/Debian)](#cuándo-usar-ufw-ubuntudebian)
- [Cuándo usar firewalld (RHEL/Fedora)](#cuándo-usar-firewalld-rhelfedora)
- [Comandos equivalentes uno a uno](#comandos-equivalentes-uno-a-uno)
- [Casos avanzados: zonas, NAT y reglas complejas](#casos-avanzados-zonas-nat-y-reglas-complejas)
- [Troubleshooting común](#troubleshooting-común)
- [Conclusión](#conclusión)
Qué son y por qué existen dos
Tanto UFW como firewalld son frontends sobre el motor de firewall del kernel Linux. No compiten entre sí en el sentido técnico: los dos terminan generando reglas en el mismo lugar. Lo que cambia es la sintaxis y la filosofía.
UFW (Uncomplicated FireWall) es el frontend que Canonical adoptó como default en Ubuntu desde 8.04 LTS. Su objetivo explícito es ser “complicated firewall for those who want to make a simple firewall” — una interfaz mínima para el caso del 90% de los usuarios: permitir SSH, permitir HTTP/HTTPS, bloquear el resto. Es un wrapper sobre iptables (que desde Ubuntu 22.04 LTS usa el backend nf_tables por defecto).
firewalld es el frontend que Red Hat adoptó desde RHEL 7 (2014), reemplazando a system-config-firewall. Tiene una filosofía distinta: separar la configuración en zonas con niveles de confianza distintos (public, trusted, dmz, internal, etc.) y permitir cambiar la zona de una interfaz sin reiniciar el firewall. Es un wrapper sobre nftables desde RHEL 8, antes sobre iptables.
Detrás de los dos, el motor fue convergiendo: a partir de 2020, ambas distros principales usan nftables como backend. Eso significa que si aprendes la sintaxis de nftables, puedes ver y auditar las reglas generadas por UFW o firewalld de la misma forma.
Antes de tocar nada, identificá qué hay corriendo en tu sistema. Esto importa porque si instalas UFW en un server que ya tiene firewalld activo, los dos van a pelear por el mismo set de hooks de netfilter — el que arrancaste último gana, el otro queda “activo” pero sin reglas efectivas:
# Ubuntu/Debian
which ufw && ufw version
# RHEL/Fedora
which firewall-cmd && firewall-cmd --version
# Ver qué hay corriendo
sudo systemctl status ufw
sudo systemctl status firewalld
# Solo uno puede estar activo a la vez
Si los dos están “inactivos”: el sistema está usando reglas de iptables/nftables raw, sin frontend. Esto pasa en servers minimalistas y containers. Si quieres un frontend, instala el que corresponda a tu distro (no mezcles).
Si los dos devuelven “active”: hay un conflicto. Pasó porque alguien instaló el otro distro. Apagá uno:
sudo systemctl stop ufw && sudo systemctl disable ufw
sudo systemctl stop firewalld && sudo systemctl disable firewalld
# Después activa solo el que quieres
sudo systemctl enable --now firewalld # o ufw
Cuándo usar UFW (Ubuntu/Debian)
UFW es la elección correcta cuando:
- Estás en Ubuntu o derivada (Linux Mint, Pop!_OS, ElementaryOS) — viene preinstalado, configurar el firewall debería tomar 30 segundos.
- Estás en Debian y quieres algo simple — instalable con
apt install ufw. - Tu server tiene una sola interfaz de red y una configuración de firewall plana (permitir SSH, HTTP, HTTPS, PostgreSQL desde una subnet específica).
- quieres reglas declarativas mínimas sin pensar en zonas.
El caso de uso clásico: acabás de provisionar un VPS en DigitalOcean, Hetzner, AWS o Vultr. quieres que el firewall esté activo con SSH permitido y el resto bloqueado. Con UFW son tres comandos:
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose
ufw allow 22/tcp agrega una regla para aceptar tráfico TCP al puerto 22 (SSH). Lo hacés antes de ufw enable porque ufw enable aplica el default deny incoming y, si no permitiste SSH antes, te quedás afuera al cerrar la sesión actual. Siempre permití SSH antes de habilitar UFW en un server remoto. La regla se guarda en /etc/ufw/user.rules y persiste entre reinicios.
ufw enable activa el firewall con la política default deny incoming, allow outgoing. Esto bloquea todo lo que entre al server desde afuera, salvo las reglas explícitas que hayas agregado. Permit outgoing por default significa que el server puede iniciar conexiones hacia afuera (DNS, NTP, apt update) sin que tengas que agregar reglas para eso.
ufw status verbose muestra las reglas activas más la política default. La primera columna es To (puerto o servicio), la segunda Action (ALLOW/DENY), la tercera From (origen). Si quieres ver números de línea (útil para borrar reglas específicas con delete), usa status numbered.
sudo ufw status verbose
# Status: active
# Logging: on (low)
# Default: deny (incoming), allow (outgoing), disabled (routed)
# New profiles: skip
#
# To Action From
# -- ------ ----
# 22/tcp ALLOW IN Anywhere
# 80/tcp ALLOW IN Anywhere
# 443/tcp ALLOW IN Anywhere
Si te quedás afuera del server después de ufw enable: el 90% de las veces es porque diste enable sin permitir SSH antes. Solución: consola KVM/IPMI del proveedor (Hetzner, DigitalOcean, AWS Lightsail, Vultr todos la ofrecen), login como root, ufw allow 22/tcp && ufw reload. Lección: nunca des ufw enable desde una sesión SSH remota sin haber permitido SSH antes.
Si quieres ver el estado en formato numerado para borrar reglas específicas:
sudo ufw status numbered
# Status: active
# To Action From
# -- ------ ----
# [ 1] 22/tcp ALLOW IN Anywhere
# [ 2] 80/tcp ALLOW IN Anywhere
# [ 3] 443/tcp ALLOW IN Anywhere
Reglas comunes para un server web básico. Cada allow agrega una regla persistente. El segundo comando permite HTTPS solo desde tu subnet corporativa — útil si tienes una VPN o VPN site-to-site:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 192.168.1.0/24 to any port 5432 proto tcp
sudo ufw reload
ufw reload aplica cambios sin tirar la sesión activa. A diferencia de enable, no cambia la política default ni resetea reglas. Útil cuando agregás reglas vía script y quieres aplicarlas de una.
Si una regla parece no aplicarse: la causa más común es que la modificaste y olvidaste hacer reload. UFW lee las reglas de /etc/ufw/user.rules solo al arrancar y en reload. ufw allow 8080/tcp lo agrega al archivo pero no las inyecta al kernel hasta que recargás. verifica con sudo iptables -L -n -v o sudo nft list ruleset (Ubuntu 22.04+).
Cuándo usar firewalld (RHEL/Fedora)
firewalld es la elección correcta cuando:
- Estás en RHEL, CentOS Stream, Rocky Linux, AlmaLinux, Fedora — viene preinstalado y es el default.
- Estás en openSUSE — el default es firewalld desde openSUSE Leap 15.
- Tu server tiene múltiples interfaces de red con niveles de confianza distintos (típico en gateways, routers, hosts de virtualización, servers con NICs separadas para management y data).
- quieres cambiar reglas en caliente sin reiniciar servicios (firewalld aplica cambios vía D-Bus sin recargar reglas existentes si usas
--permanent=false). - Tu organización usa playbooks Ansible contra fleets de RHEL — el módulo
ansible.posix.firewalldes robusto y testeado.
El caso de uso clásico: server RHEL con dos NICs: eth0 en la red pública (internet) y eth1 en la red privada de la empresa. quieres reglas distintas para cada una, y quieres poder mover un server de zona sin reescribir reglas. Eso es justo el caso para el que firewalld fue diseñado.
Concepto clave de firewalld: las zonas. Cada zona es un set predefinido de reglas con un nivel de confianza. Las zonas default que trae:
- trusted: confía en todo. Equivale a no tener firewall para esa interfaz.
- public: la default. Permite servicios que tú definas explícitamente; bloquea el resto.
- internal: para redes internas confiables. Permite más servicios por default que public (DHCP, SSH, samba, etc.).
- dmz: zona desmilitarizada. Servicios expuestos a internet pero con acceso restringido a la red interna.
- external: para redes externas donde masquerading está habilitado.
- block: rechaza todas las conexiones entrantes, pero responde con
icmp-host-prohibited(el origin sabe que el server existe pero no le interesa). - drop: descarta silenciosamente. El origin no recibe respuesta, parece que el server no existe.
Para ver qué zonas hay activas y qué interfaces están asignadas a cuál:
sudo firewall-cmd --get-active-zones
# public
# interfaces: eth0
# internal
# interfaces: eth1
Si no hiciste nada, todo está en public. Para un server típico, lo primero que hacés es asegurarte de que SSH está permitido en la zona donde está tu interfaz de management (normalmente public).
sudo firewall-cmd --zone=public --add-service=ssh --permanent
sudo firewall-cmd --reload
--add-service=ssh agrega el servicio ssh (definido en /usr/lib/firewalld/services/ssh.xml, que internamente es TCP/22) a la zona. --permanent guarda el cambio en la configuración persistente (/etc/firewalld/). Sin --permanent, el cambio es runtime — se aplica al firewall que está corriendo ahora, pero desaparece al reiniciar o hacer firewalld --reload. Siempre usa --permanent salvo que estés probando algo y quieres descartar el cambio en el próximo reload.
firewall-cmd --reload recarga la configuración persistente al runtime. Diferencia crítica con UFW: --reload en firewalld resetea el estado runtime — si tienes cambios temporales sin --permanent, se pierden. Para agregar algo temporal sin perderlo, usa --add-service=X sin --permanent y NO recargues.
Si te quedás afuera por deshabilitar SSH en firewalld: igual que UFW, usa consola KVM/IPMI del proveedor. En RHEL con SELinux, es más probable que el bloqueo sea por SELinux que por firewalld. sudo ausearch -m avc --start recent | grep sshd te dice si SELinux rechazó algo.
Ver las reglas activas. La opción --list-all te muestra la zona default con sus reglas completas. --zone= te permite ver otra zona específica:
sudo firewall-cmd --list-all
# public (active)
# target: default
# icmp-block-inversion: no
# interfaces: eth0
# sources:
# services: cockpit dhcpv6-client ssh
# ports:
# protocols:
# forward: no
# masquerade: no
# forward-ports:
# source-ports:
# icmp-blocks:
# rich rules:
Comandos equivalentes uno a uno
Para que la diferencia sea concreta, esta tabla traduce los comandos más comunes de uno al otro. Te sirve si administras servers heterogéneos (algunos Ubuntu, algunos RHEL) y quieres tener un mapa mental rápido:
| Operación | UFW | firewalld |
|---|---|---|
| Ver estado | sudo ufw status verbose |
sudo firewall-cmd --state && sudo firewall-cmd --list-all |
| Habilitar firewall | sudo ufw enable |
sudo systemctl enable --now firewalld |
| Permitir SSH | sudo ufw allow 22/tcp |
sudo firewall-cmd --zone=public --add-service=ssh --permanent && sudo firewall-cmd --reload |
| Permitir HTTP | sudo ufw allow 80/tcp |
sudo firewall-cmd --zone=public --add-service=http --permanent && sudo firewall-cmd --reload |
| Permitir HTTPS | sudo ufw allow 443/tcp |
sudo firewall-cmd --zone=public --add-service=https --permanent && sudo firewall-cmd --reload |
| Permitir desde subnet | sudo ufw allow from 10.0.0.0/24 to any port 5432 |
sudo firewall-cmd --zone=internal --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=5432 protocol=tcp accept' --permanent && sudo firewall-cmd --reload |
| Permitir servicio custom | sudo ufw allow 8080/tcp |
sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent && sudo firewall-cmd --reload |
| Borrar regla | sudo ufw delete allow 80/tcp o sudo ufw status numbered && sudo ufw delete N |
sudo firewall-cmd --zone=public --remove-service=http --permanent && sudo firewall-cmd --reload |
| Ver reglas activas | sudo iptables -L -n -v o sudo nft list ruleset |
sudo firewall-cmd --list-all o sudo iptables -L -n -v |
| Resetear a default | sudo ufw reset |
No hay equivalente directo. --complete-reload solo descarta el estado runtime; para reset real hay que borrar los XML de zona en /etc/firewalld/zones/ y recargar |
Si quieres ver las reglas nativas del kernel (lo que UFW/firewalld terminaron generando), ambos terminan en iptables (legacy) o nftables (moderno). Para verlas sin el frontend:
# Ubuntu 22.04 y anteriores, RHEL 7
sudo iptables -L -n -v
sudo iptables -t nat -L -n -v
# Ubuntu 22.04+, RHEL 8+, Fedora
sudo nft list ruleset
Cuando debuggeás un problema de conectividad (“puerto X no responde”), lo mejor es ver las reglas nativas, no el frontend. UFW a veces tiene reglas en user.rules que no se aplicaron (olvidaste reload); firewalld tiene reglas en runtime que no están en --permanent (hiciste el cambio sin --permanent). Las reglas en el kernel son la fuente de verdad.
Casos avanzados: zonas, NAT y reglas complejas
Donde firewalld saca ventaja clara es en escenarios con múltiples interfaces o NAT. UFW también puede hacer esto (todo lo que UFW hace, firewalld también, y viceversa — solo cambia la sintaxis), pero la sintaxis de firewalld es más legible cuando las reglas se vuelven densas.
Caso 1: server con dos NICs (DMZ típica)
eth0 en red pública (203.0.113.0/24), eth1 en red privada (10.10.0.0/24). eth0 expone HTTPS al mundo; eth1 expone PostgreSQL solo a la red interna. Cada NIC va a una zona distinta:
sudo firewall-cmd --zone=public --change-interface=eth0 --permanent
sudo firewall-cmd --zone=internal --change-interface=eth1 --permanent
sudo firewall-cmd --zone=public --add-service=https --permanent
sudo firewall-cmd --zone=internal --add-port=5432/tcp --permanent
sudo firewall-cmd --reload
--change-interface mueve la NIC a la zona. Sin esto, ambas interfaces quedan en public y las reglas se aplican a las dos indistintamente. La asignación persistente queda en /etc/firewalld/zones/public.xml y /etc/firewalld/zones/internal.xml.
Si te aparece “ZONE_ALREADY_SET” o “NAME_CONFLICT”: la interfaz ya tiene una zona asignada desde NetworkManager. usa nmcli connection show para ver qué conexiones de red hay y nmcli connection modify "nombre" connection.zone internal para asignar la zona desde NetworkManager (que es el método recomendado en RHEL/Fedora donde NetworkManager controla las interfaces).
Caso 2: NAT / masquerading
Server con IP pública 203.0.113.10 que comparte internet a una red privada 10.10.0.0/24 (hace SNAT). Esto es el caso típico de un gateway:
sudo firewall-cmd --zone=external --add-interface=eth0 --permanent
sudo firewall-cmd --zone=internal --add-interface=eth1 --permanent
sudo firewall-cmd --zone=external --add-masquerade --permanent
sudo firewall-cmd --reload
--add-masquerade activa SNAT para todo el tráfico que sale por la zona external. Equivalente a iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE. Sin esto, los hosts de la red interna pueden salir al mundo pero las respuestas vuelven con la IP privada como destino y no saben a quién entregarlas.
Si después de habilitar masquerade los hosts internos pueden salir pero no reciben respuestas: el problema suele ser que falta ip_forward=1 en el kernel. verifica con cat /proc/sys/net/ipv4/ip_forward — tiene que dar 1. Si da 0, sudo sysctl -w net.ipv4.ip_forward=1 lo activa en runtime; para hacerlo persistente, agregá net.ipv4.ip_forward=1 a /etc/sysctl.d/99-custom.conf y sudo sysctl -p.
Caso 3: port forwarding
Server que recibe tráfico en 443 (eth0, público) y lo redirige a un container Docker que escucha en 127.0.0.1:8443. Caso típico de reverse proxy:
sudo firewall-cmd --zone=public --add-forward-port=port=443:proto=tcp:toport=8443:toaddr=127.0.0.1 --permanent
sudo firewall-cmd --reload
add-forward-port configura DNAT para redirigir el tráfico. El formato es port=X:proto=tcp:toport=Y:toaddr=Z. Si no especificás toaddr, firewalld asume que es la misma IP de origen del paquete (útil cuando redirigís entre interfaces).
Si el port forwarding no funciona: chequea tres cosas. 1) Que el servicio que escucha en el puerto destino (8443 en el ejemplo) esté realmente arriba: ss -tlnp | grep 8443. 2) Que el módulo nf_nat esté cargado en el kernel: lsmod | grep nf_nat. 3) Que SELinux no esté bloqueando: sudo ausearch -m avc --start recent | grep -E "(firewalld|iptables)". En RHEL con SELinux enforcing, el port forwarding requiere que la boolean httpd_can_network_relay esté activa: sudo setsebool -P httpd_can_network_relay 1.
Troubleshooting común
“ufw: command not found” en Ubuntu
UFW no viene preinstalado en Ubuntu Server minimal ni en algunas imágenes cloud oficiales. instala:
sudo apt update && sudo apt install ufw
sudo ufw allow 22/tcp && sudo ufw enable
“firewall-cmd: command not found” en RHEL
El paquete firewalld no se instaló (puede pasar en imágenes “minimal” de RHEL). instala:
sudo dnf install firewalld
sudo systemctl enable --now firewalld
Las reglas no aparecen después de --reload
El reload lee /etc/firewalld/ (config persistente) y lo aplica al runtime. Si modificaste las reglas sin --permanent, no se guardaron — solo viven en runtime hasta el próximo reload. verifica: sudo firewall-cmd --list-all (runtime) vs sudo firewall-cmd --list-all --permanent (persistente). Si solo aparecen en el primero, no se guardaron.
UFW deja de funcionar después de actualizar Docker
Docker modifica iptables/nftables directamente al arrancar containers, ignorando UFW. Esto es by design — Docker asume que sabes lo que hacés. Si quieres que Docker respete UFW, agregá DOCKER_OPTS="--iptables=false" a /etc/default/docker y reiniciá Docker. Cuidado: con --iptables=false, Docker no expone puertos al mundo — tienes que agregar reglas UFW a mano para cada puerto que publiques. Alternativa: usa firewalld en RHEL, que sí se integra bien con Docker vía nftables.
Las reglas parecen aplicarse pero el tráfico igual se bloquea
Casi siempre hay otro firewall delante: el del proveedor cloud (AWS Security Group, GCP Firewall, Azure NSG), o el del hypervisor, o un WAF (Cloudflare, AWS WAF). UFW/firewalld controlan solo el firewall del sistema operativo. Para confirmar: sudo iptables -L -n -v muestra las reglas locales; si el tráfico no aparece bloqueado ahí pero igual no llega, está bloqueado aguas arriba.
Cambios en firewalld se pierden al reiniciar el server
Olvidaste --permanent. Todos los cambios sin --permanent son runtime. verifica con --list-all --permanent que estén todas las reglas ahí. Si falta alguna, sudo firewall-cmd --runtime-to-permanent migra todas las reglas runtime a persistente en una sola operación.
Conclusión
La regla de oro: usa el firewall que viene por defecto en tu distro. Si administras un server Ubuntu/Debian, UFW es la respuesta; si es RHEL/Fedora, firewalld. Los dos terminan haciendo lo mismo a nivel kernel — solo cambia la sintaxis. Para el caso típico de un server web simple, ambos te llevan al mismo lugar en 30 segundos. Cuando el escenario se vuelve complejo (múltiples interfaces, NAT, port forwarding), firewalld tiene una sintaxis más legible gracias al concepto de zonas, pero UFW puede hacer exactamente lo mismo si conocés la sintaxis de reglas equivalentes. Próximos pasos: revisa las reglas que tienes actualmente con ufw status o firewall-cmd --list-all, asegurate de que el default es deny incoming, y verifica que solo estén permitidos los puertos que tu server realmente necesita.
Lee también: [Configurar firewall Linux con nftables](/configurar-firewall-linux-nftables-reemplazo-iptables/) si quieres entender qué pasa debajo del frontend, o [Fail2ban para proteger SSH](/fail2ban-proteger-servidor-ssh-ataques-fuerza-bruta/) para mitigar intentos de fuerza bruta sobre los puertos que dejaste abiertos.
Preguntas frecuentes
¿Por qué UFW vs firewalld: cuál usar según tu distribución Linux 2026 es relevante para sysadmins Linux?
Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.
¿Qué necesito para empezar con UFW vs firewalld: cuál usar?
Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.
¿Cuáles son los errores más comunes con UFW vs firewalld: cuál usar?
Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.
¿Cuándo usar UFW vs firewalld: cuál usar y cuándo una alternativa?
Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.
¿Cómo migro desde una configuración previa a UFW vs firewalld: cuál usar?
Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.
Lee también
- Guía Fedora 44: Novedades, Instalación y Upgrade para Sysadmins Linux
- Configura VLANs en Linux con nmcli: Guía paso a paso para sysadmins
- Protege tu SSH: Guía esencial para configurar Fail2ban en Linux
- Guía Definitiva: Configura Kubernetes con kubeadm en Ubuntu para Sysadmins Linux
- Configura Prometheus y Grafana: Guía DevOps para SysAdmins Linux

Pingback: ¿Cuánta memoria swap necesita tu servidor Linux? (guía 2026)