SSD Nodes Learn 🎉 VPS desde $5.50/mes
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-12

Configurar firewalld en Rocky Linux y AlmaLinux

Aprenda a gestionar puertos, zonas y reglas en Rocky o AlmaLinux. Evite bloqueos accidentales, use el flag --permanent correctamente y asegure su VPS tras reiniciar el servicio.

Qué es firewalld y por qué Rocky y AlmaLinux lo incluyen

firewalld es el gestor de firewall instalado por defecto en Rocky Linux, AlmaLinux y otras distribuciones basadas en Red Hat Enterprise Linux (RHEL). No inspecciona paquetes por sí mismo. Mantiene una configuración guardada y la traduce en reglas de nftables. Un comando, firewall-cmd, permite editarla mientras el servidor permanece en línea.

Si ya conoce cómo funciona ufw en un VPS con Ubuntu, ya conoce su función. firewalld añade dos conceptos que ufw no tiene. El primero son las zonas: una política con nombre en la que se clasifican los paquetes. El segundo es la separación entre las reglas activas y las reglas guardadas, lo cual se gestiona mediante el flag --permanent y es la mayor fuente de confusión en esta herramienta.

Todo lo que aparece a continuación es un comando que debe ejecutar en su propio servidor. Pruebe cada cambio desde una segunda máquina, ya que una regla que parece correcta desde el equipo local puede ser errónea desde Internet.

Abra SSH antes de realizar cualquier otra acción

La mayoría de las instalaciones de Rocky y AlmaLinux incluyen firewalld activo de forma predeterminada, y la configuración que se distribuye permite SSH. Algunas imágenes mínimas de la nube lo eliminan. Verifique en lugar de asumir.

sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --state

firewall-cmd --state imprime running. Si el servicio está detenido, cualquier otra llamada a firewall-cmd responde FirewallD is not running y finaliza con un código distinto de cero. Eso es lo primero que debe comprobar cuando un comando parece no hacer nada en absoluto.

Ahora lea lo que está permitido actualmente.

sudo firewall-cmd --list-all

La salida real tiene algunas líneas más. Estas son las que importan:

public (active)
  target: default
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  rich rules:

ssh en la línea services: es la razón por la que su sesión sigue funcionando. Si falta, añádalo antes de tocar cualquier otra cosa, porque iniciar un firewall sin una regla SSH termina la sesión y no le permitirá volver a entrar.

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

target: default significa que un paquete que no coincide con nada es rechazado con una respuesta ICMP (internet control message protocol) de host prohibido, por lo que un cliente que intenta acceder a un puerto cerrado ve No route to host inmediatamente. Establecer el objetivo en DROP hace que el servidor permanezca en silencio, y los escáneres entonces esperan a que se agote el tiempo de espera.

sudo firewall-cmd --permanent --zone=public --set-target=DROP
sudo firewall-cmd --reload

Conozca el coste antes de ejecutar eso: DROP también impide que el servidor responda a ping, por lo que su propia monitorización también dejará de recibir datos.

¿Por qué desapareció mi regla? El flag --permanent

firewalld mantiene dos configuraciones simultáneamente. La configuración en tiempo de ejecución es la que el kernel aplica en este preciso instante. La configuración permanente es la que reside en /etc/firewalld/zones/public.xml y la que se recupera tras una recarga o un reinicio.

Un comando sin --permanent cambia solo el tiempo de ejecución. Funciona de inmediato y desaparece en la siguiente recarga o arranque. Un comando con --permanent escribe el archivo y no cambia nada de lo que se está ejecutando, por lo que el puerto permanece cerrado hasta que realice una recarga. Ninguno de estos comportamientos es un error. Ambos sorprenden a los usuarios, ya que el comando imprime success en ambos casos.

Escriba el par cada vez.

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

Puede leer ambas configuraciones, lo cual es la forma más rápida de averiguar cuál de los dos errores cometió.

sudo firewall-cmd --list-services
sudo firewall-cmd --permanent --list-services

El primero imprime el conjunto activo. El segundo imprime el conjunto guardado. Si el conjunto activo contiene un servicio que el conjunto guardado no tiene, esa regla desaparecerá en la siguiente recarga. Si el conjunto guardado contiene uno que el conjunto activo no tiene, olvidó realizar la recarga. sudo firewall-cmd --runtime-to-permanent copia todo lo activo al archivo guardado, lo cual es útil después de una sesión de pruebas.

--reload mantiene el estado del seguimiento de conexiones, por lo que su sesión SSH sobrevive a la operación. --complete-reload recarga también los módulos del kernel y pierde dicho estado, lo que normalmente termina todas las conexiones abiertas, incluida la suya. Utilice la recarga simple.

Existe una red de seguridad integrada. Una regla de tiempo de ejecución puede expirar por sí misma.

sudo firewall-cmd --add-service=http --timeout=5m

Esa regla se elimina sola después de cinco minutos. No se puede combinar con --permanent, y ese es el objetivo: existe para probar un cambio del que no está seguro. La red de seguridad más antigua es mejor. Mantenga una segunda sesión SSH abierta mientras edita las reglas y no la cierre hasta que un nuevo inicio de sesión confirme que las nuevas reglas funcionan.

Zonas, y por qué solo la zona predeterminada importa en un VPS

Una zona es un conjunto de permisos con nombre al que se le asigna un nivel de confianza. firewalld coloca cada paquete entrante en exactamente una zona. Primero, compara la dirección de origen del paquete con la lista sources: de cada zona. Si no hay coincidencias, utiliza la zona a la que está vinculada la interfaz entrante. Si la interfaz no está vinculada a ninguna zona, el paquete se dirige a la zona predeterminada.

sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones

En un VPS con una sola interfaz de red, la respuesta casi siempre es public, y esa es la única zona que utilizará. firewall-cmd sin el argumento --zone= actúa sobre la zona predeterminada; por eso, cada comando corto de esta guía funciona sin necesidad de especificar una.

Este es el fallo que hace perder toda una tarde. Si la interfaz está vinculada a otra zona, sus reglas se aplican en public mientras el tráfico se gestiona en otro lugar, por lo que nada de lo que añada tendrá efecto y no recibirá ninguna advertencia. --get-active-zones muestra la vinculación:

public
  interfaces: eth0

Si la interfaz aparece bajo un nombre de zona diferente, escriba sus reglas allí usando --zone= o mueva la interfaz.

sudo firewall-cmd --permanent --zone=public --change-interface=eth0
sudo firewall-cmd --reload

NetworkManager gestiona las interfaces en Rocky y AlmaLinux, y restablece la zona cuando se activa la conexión. Defínala también allí para que un reinicio no deshaga su trabajo. Obtenga el nombre de la conexión del primer comando, ya que rara vez coincide con el nombre del dispositivo.

sudo nmcli connection show
sudo nmcli connection modify "System eth0" connection.zone public

La coincidencia por origen tiene prioridad sobre la coincidencia por interfaz; así es como una dirección obtiene una política diferente. La zona integrada trusted acepta todo.

sudo firewall-cmd --permanent --zone=trusted --add-source=203.0.113.10/32
sudo firewall-cmd --reload

Tenga cuidado con esa zona. Abre todos los puertos del servidor a esa dirección, incluida la base de datos que usted consideraba privada. Utilice una regla enriquecida (rich rule) cuando desee abrir un solo puerto, no un host completo.

¿Qué es un servicio de firewalld?

Un servicio es un conjunto de puertos con nombre que se distribuye como un archivo XML. --add-service=https abre 443/tcp porque /usr/lib/firewalld/services/https.xml define lo que significa https.

sudo firewall-cmd --get-services
sudo firewall-cmd --info-service=https

--info-service imprime los puertos que se ocultan tras el nombre:

https
  ports: 443/tcp

Utilice el nombre cuando exista uno. Su lectura es clara en --list-all seis meses después, y paquetes como Cockpit instalan su propio archivo de servicio. Utilice --add-port para cualquier cosa que no tenga una definición.

La brecha que debe vigilar: el servicio ssh significa 22/tcp y nada más. Si cambió SSH a otro puerto mientras reforzaba el acceso SSH en el servidor, entonces --add-service=ssh no abre el puerto que realmente utiliza.

sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload

En una reinstalación de RHEL existe un segundo bloqueo en esa puerta. SELinux (security-enhanced Linux) etiqueta los números de puerto, y sshd no tiene permiso para vincularse a un puerto fuera de sus etiquetas. Entonces se niega a iniciar y el registro muestra error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.. Etiquete el puerto primero.

sudo dnf install -y policycoreutils-python-utils
sudo semanage port -a -t ssh_port_t -p tcp 2222

¿Cómo puedo ver qué está abierto en este momento?

sudo firewall-cmd --list-all
sudo firewall-cmd --list-rich-rules
sudo nft list table inet firewalld | head -n 40

Los dos primeros comandos informan sobre lo que firewalld tiene registrado. El tercero lee las reglas que el kernel aplica realmente en la tabla que gestiona firewalld. Ambos deben coincidir.

Nada de esto es una prueba definitiva. Realice la prueba desde otra máquina:

nc -zv 203.0.113.20 443

No ejecute la prueba en el propio servidor. firewalld acepta todo el tráfico que llega a través de la interfaz loopback, por lo que curl http://localhost:8080 tendrá éxito independientemente de lo que indiquen sus reglas. Esa prueba solo confirma que el servicio está activo. No proporciona información sobre el estado del firewall.

Permitir un puerto web

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

El último comando debería listar ahora http https junto con lo que ya aparecía anteriormente. Si el sitio sigue sin responder, es posible que el cortafuegos no sea el problema. Una regla permite el paso de un paquete. Un proceso todavía debe estar escuchando en él.

sudo ss -tlnp

Un socket que aparece como 0.0.0.0:443 o *:443 acepta conexiones desde cualquier dirección. Uno que aparece como 127.0.0.1:443 responde solo en loopback, y ninguna regla de cortafuegos hará que sea accesible desde el exterior. Puertos y sockets de escucha en Linux cubre esa diferencia con más detalle.

¿Cómo cierro un puerto de nuevo?

sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --reload

La regla --permanent también se aplica aquí, y su efecto es más crítico en esta dirección. Si elimina un servicio solo del entorno de ejecución, el puerto parecerá cerrado, pero el siguiente reinicio o recarga lo abrirá de nuevo desde el archivo guardado. Es una vulnerabilidad que pasará inadvertida, ya que la comprobación que ejecutó resultó exitosa.

Eliminar algo que nunca existió imprime Warning: NOT_ENABLED: http y aun así termina con código 0. Añadir el mismo elemento dos veces imprime Warning: ALREADY_ENABLED: http. Ambas operaciones son seguras. Un nombre mal escrito es distinto: Error: INVALID_SERVICE significa que firewalld no tiene ninguna definición con ese nombre y no se ha realizado ningún cambio.

Si su --list-all muestra cockpit y usted no utiliza la consola web Cockpit en el puerto 9090, elimínelo. Cada puerto abierto es un servicio que debe mantener actualizado con parches.

Restringir un puerto a una dirección de origen

Las reglas enriquecidas (rich rules) son la forma extendida para cuando un nombre de servicio simple no puede expresar lo que se necesita. Restringir SSH a una dirección de oficina requiere dos comandos, y el segundo es el que la gente suele olvidar.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" service name="ssh" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload

Una zona es un conjunto de permisos, no una lista numerada que se detiene en la primera coincidencia. La regla enriquecida añade una aceptación para una dirección. No deniega a nadie más. Mientras ssh siga en la línea services:, todo internet seguirá llegando al puerto 22 y la regla enriquecida no cambiará nada que se pueda medir. Elimine la entrada general, o la específica será solo decorativa.

Para un puerto sin nombre de servicio, especifique el puerto en su lugar.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" port port="5432" protocol="tcp" accept'

Para descartar una red ruidosa y mantener un registro, coloque el elemento de log antes de la acción, que es el orden que espera el lenguaje de reglas enriquecidas.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" log prefix="fw-drop " level="info" limit value="3/m" drop'
sudo firewall-cmd --reload
sudo journalctl -k -g fw-drop

El valor limit detiene una inundación de paquetes que llene el journal. Antes de bloquear SSH a una única dirección, asegúrese de que esa dirección sea estable. Una conexión doméstica con una dirección IP cambiante le dejará fuera el día que esta cambie, así que pruebe y verifique primero el acceso a la consola de su proveedor.

Comandos de ufw y sus equivalentes en firewall-cmd

Mismas tareas, distinta herramienta. Cada línea --permanent necesita un sudo firewall-cmd --reload después, que es lo único que una lista como esta no puede mostrarle.

  • sudo ufw enable se convierte en sudo systemctl enable --now firewalld
  • sudo ufw disable se convierte en sudo systemctl disable --now firewalld
  • sudo ufw status verbose se convierte en sudo firewall-cmd --list-all
  • sudo ufw allow OpenSSH se convierte en sudo firewall-cmd --permanent --add-service=ssh
  • sudo ufw allow 443/tcp se convierte en sudo firewall-cmd --permanent --add-port=443/tcp
  • sudo ufw delete allow 443/tcp se convierte en sudo firewall-cmd --permanent --remove-port=443/tcp
  • sudo ufw allow from 203.0.113.10 to any port 22 se convierte en la regla enriquecida mostrada arriba
  • sudo ufw reload se convierte en sudo firewall-cmd --reload
  • sudo ufw default deny incoming es ya como se comporta la zona public, y --set-target=DROP es su versión silenciosa
  • sudo ufw logging on se convierte en sudo firewall-cmd --set-log-denied=all

Vale la pena aclarar una diferencia. ufw mantiene una lista numerada y permite insertar una regla en la posición 1. firewalld no tiene números de regla, por lo que "poner esta regla primero" no tiene significado aquí. Cuando dos entradas de firewalld parecen contradecirse, gana la aceptación general, ya que nada en el conjunto deniega. Usted debe eliminar la entrada general manualmente.

¿Por qué mi contenedor Docker es accesible si el firewall parece cerrado?

Porque un puerto de contenedor publicado nunca llega a la parte del firewall que controla su zona. docker run -d -p 8080:80 nginx le indica a Docker que escriba sus propias reglas de NAT (traducción de direcciones de red) y reenvío. Un paquete que llega al puerto 8080 se reescribe y se enruta hacia el contenedor, por lo que se reenvía en lugar de entregarse al host. Las líneas services: y ports: de su zona gobiernan los paquetes entregados al host. Las reglas de Docker gobiernan la ruta de reenvío y estas aceptan el tráfico.

El resultado es un servidor donde sudo firewall-cmd --list-all no muestra el puerto 8080 y nc -zv 203.0.113.20 8080 desde otra máquina se conecta de todos modos. Observe lo que Docker instaló:

sudo iptables -t nat -L DOCKER -n

La solución reside en el flag de publicación. Vincule el puerto a la interfaz de loopback y coloque un proxy inverso delante.

docker run -d -p 127.0.0.1:8080:80 nginx

El contenedor ahora responde a curl http://127.0.0.1:8080 en el servidor y a nada desde el exterior. Los usuarios de Ubuntu se encuentran con el mismo obstáculo, descrito en por qué los contenedores Docker publican puertos saltándose ufw. Podman con privilegios de root, que Rocky y AlmaLinux incluyen en sus repositorios base, publica puertos con el mismo enfoque de NAT, así que realice pruebas desde otra máquina en lugar de confiar en la lista de la zona.

Hacer que sobreviva a un reinicio y los errores que encontrará

sudo systemctl is-enabled firewalld
sudo systemctl status firewalld

enabled y active (running) son lo que usted necesita. Un firewall que está en ejecución pero no habilitado le protege hasta el primer reinicio. Esa comprobación debe estar en la lista que sigue en los primeros diez minutos en un VPS nuevo, junto a las claves SSH y las actualizaciones.

Los comandos directos de nftables y firewalld no son compatibles. firewalld es propietario de una tabla llamada inet firewalld. sudo nft flush ruleset la elimina, el servidor queda expuesto a todo y firewall-cmd --list-all sigue mostrando su configuración prevista, porque firewalld informa de lo que cree en lugar de lo que el kernel contiene realmente. sudo firewall-cmd --reload reinstala las reglas. Escriba las reglas con firewall-cmd para que se mantengan tras una recarga.

Dos gestores de firewall en un mismo servidor. Instalar ufw o iptables-services junto a firewalld le deja con dos programas escribiendo reglas sin conocimiento del otro; el ganador depende de qué servicio se inició al final. Elija uno. En Rocky y AlmaLinux, firewalld es el que cuenta con soporte de la distribución.

El firewall del proveedor frente al servidor. Muchos paneles de VPS tienen un firewall de red independiente. Si --list-all muestra un puerto abierto y una conexión desde el exterior sigue fallando, revise el panel antes de cambiar nada en el servidor. También funciona a la inversa: una regla abierta en el panel no hace nada mientras firewalld rechace el paquete.

Ejecutar firewall-cmd sin sudo. Cada cambio requiere privilegios de root. Sin ellos, la solicitud es rechazada por una comprobación de autorización y no se modifica nada, lo que a simple vista parece como si el comando hubiera sido ignorado.

Seis comandos cubren la mayoría de los días: --list-all para leer el estado, --permanent --add-service o --add-port para abrir algo, --permanent --remove-service para cerrarlo, --reload para aplicar el archivo guardado y --runtime-to-permanent después de una ronda de experimentos. La zona es public, el flag es --permanent y la única comprobación fiable proviene de otra máquina.

FAQ

¿Por qué desapareció mi regla de firewalld tras reiniciar?

La regla se aplicó únicamente a la configuración en tiempo de ejecución. sudo firewall-cmd --add-service=http tiene efecto inmediato pero se descarta en el siguiente reinicio o recarga, ya que la configuración guardada en /etc/firewalld/zones/public.xml no se modificó. Añada --permanent y luego ejecute sudo firewall-cmd --reload. Para conservar las reglas que ya añadió manualmente, ejecute sudo firewall-cmd --runtime-to-permanent, lo cual copia el conjunto activo al archivo de configuración guardada.

¿Por qué no cambia nada después de añadir una regla con --permanent?

Porque --permanent escribe el archivo pero no altera el firewall en ejecución. El puerto permanece cerrado hasta que sudo firewall-cmd --reload carga la configuración guardada en el kernel. Compare sudo firewall-cmd --list-services con sudo firewall-cmd --permanent --list-services: si la lista guardada contiene una entrada que no está en la lista activa, lo que le falta es la recarga.

¿Debo usar --add-service o --add-port?

Use --add-service cuando exista un nombre para lo que ejecuta. Esto declara su intención y sudo firewall-cmd --info-service=https muestra exactamente qué puertos cubre dicho nombre. Use --add-port cuando nada defina su servicio o cuando este escuche en un puerto no estándar. El servicio ssh implica solo 22/tcp, por lo que si SSH se mueve al 2222, necesita --add-port=2222/tcp además de una etiqueta SELinux para ese puerto.

¿Por qué mi contenedor Docker es accesible cuando firewall-cmd muestra el puerto cerrado?

Un puerto publicado es reescrito por las reglas NAT de Docker y redirigido al contenedor, por lo que el paquete nunca se entrega al host; las listas de servicios y puertos de una zona solo cubren los paquetes entregados al host. El contenedor responde desde internet mientras --list-all no muestra nada. Publique en el loopback en su lugar, con docker run -d -p 127.0.0.1:8080:80 nginx, y coloque un proxy inverso delante.

¿Puedo instalar ufw en Rocky Linux en lugar de firewalld?

Dos gestores de firewall en un mismo servidor escriben reglas sin conocerse entre sí, y el conjunto que prevalece depende de qué servicio se inició al final. firewalld es la herramienta soportada en Rocky Linux y AlmaLinux, ya viene instalada y controla el mismo backend de nftables que usaría ufw. Aprenda a manejar la zona predeterminada y el flag --permanent y dominará toda la herramienta.