SSD Nodes Learn 🎉 VPS desde $5.50/mes
Guías Matt ConnorPor Matt Connor

Cambiar el puerto SSH con SELinux y firewalld

Aprenda a cambiar el puerto SSH en Rocky Linux y AlmaLinux sin perder la sesión: configure firewalld, el contexto SELinux y sshd_config en el orden correcto.

Por qué cambiar el puerto SSH requiere tres pasos aquí

Para cambiar el puerto SSH en Rocky Linux, AlmaLinux, CentOS Stream o Fedora, una sola edición no es suficiente. Tres sistemas independientes intervienen para determinar si funciona una conexión en el puerto nuevo. firewalld decide si el paquete llega al equipo. SELinux decide si sshd puede asociarse a ese número de puerto. sshd_config determina qué puerto solicita el daemon. Si omite el paso de SELinux, el daemon no se inicia. Si omite el paso de firewalld, se inicia y escucha, pero nadie puede acceder a él.

En Ubuntu, la misma tarea requiere una edición y un reinicio, porque Ubuntu usa AppArmor en lugar de SELinux y no incluye ningún perfil que restrinja los puertos a los que sshd puede asociarse. Si ufw está activo, debe añadir una regla. Esa es toda la diferencia. La familia RHEL incluye firewalld activo y SELinux en modo enforcing en una instalación nueva, y ambos tienen en cuenta los números de puerto.

Realice el trabajo en este orden para que la sesión actual permanezca activa durante todos los pasos:

  1. Abra el puerto nuevo en firewalld y mantenga abierto el puerto 22 por ahora.
  2. Añada la etiqueta de SELinux para el puerto nuevo con semanage.
  3. Establezca el puerto en la configuración de sshd.
  4. Reinicie sshd y, después, inicie sesión en el puerto nuevo desde un segundo terminal antes de cerrar el primero.
Busque la consola web de su proveedor (VNC o serie) antes de empezar y compruebe que puede iniciar sesión mediante ella. Esa consola permite recuperar el acceso si el cambio sale mal. Un cambio de puerto es uno de los motivos más habituales por los que un usuario se queda sin acceso a un servidor que acaba de contratar.

Primero, instale semanage

semanage es la herramienta que edita la configuración de políticas de SELinux, y una instalación mínima de Rocky Linux o AlmaLinux no la incluye. Se encuentra en policycoreutils-python-utils.

sudo dnf install -y policycoreutils-python-utils

Si ejecuta el comando antes de instalar ese paquete, aparece sudo: semanage: command not found. En ese punto, muchos lectores concluyen que SELinux no está instalado y omiten el paso. SELinux sí está instalado. Sólo falta la herramienta de administración. Si la sintaxis de dnf es nueva para usted, las equivalencias de comandos de dnf y apt le permiten relacionarla con lo que ya conoce.

Elija un puerto y compruebe que ningún proceso lo esté usando

Puede usar cualquier puerto TCP libre entre 1024 y 65535. Haga estas dos comprobaciones antes de elegirlo:

sudo ss -tlnp | grep -w 2222
sudo semanage port -l | grep -w 2222

La primera muestra si algún proceso ya está escuchando en ese número. La segunda muestra si la política de SELinux ya se lo asigna a otro tipo de servicio. Un puerto libre no devuelve ningún resultado en ninguna de las dos comprobaciones. Si la política ya lo reclama, el semanage port -a del paso 2 falla con ValueError: Port tcp/2222 already defined. La solución es elegir otro número.

En esta guía se usa 2222 como ejemplo. También es el primer puerto que prueba un escáner después del 22, así que en un servidor real elija un número menos evidente.

Paso 1: abrir el puerto en firewalld

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

--permanent escribe la regla en el archivo de zona del disco y no modifica el firewall en ejecución. --reload carga la configuración del disco en el firewall en ejecución. Si omite la recarga, la regla existe, pero no tiene efecto hasta que firewalld se reinicie. Esta es una de las formas más habituales en que todo el procedimiento parece fallar sin motivo.

Por ahora, no modifique la entrada de servicio ssh. Esa entrada mantiene abierto el puerto 22 y es su vía de recuperación mientras realiza las pruebas.

Revise también el panel de control de su proveedor. Muchos proveedores ejecutan un firewall de red delante de la VPS, fuera del sistema operativo. Por eso, el tráfico destinado a un puerto abierto en firewalld todavía puede descartarse en la red del proveedor. La guía básica de firewalld para una VPS explica las zonas y la diferencia entre la configuración en ejecución y la configuración permanente si este modelo es nuevo para usted.

Paso 2: etiquetar el puerto para SELinux

sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -l | grep ssh_port_t

-a añade una nueva asignación de puerto. -t ssh_port_t es el tipo que llevan los puertos SSH. El segundo comando muestra todo lo que ssh_port_t cubre ahora, para que pueda confirmar que el número se añadió antes de modificar el daemon.

Por qué SELinux bloquea el puerto

SELinux (security-enhanced Linux) asigna una etiqueta a cada objeto del sistema, y los números de puerto TCP son objetos como cualquier otro. El daemon SSH se ejecuta confinado en un dominio llamado sshd_t. La política permite que sshd_t se asocie a puertos TCP etiquetados como ssh_port_t, y, de forma predeterminada, el único puerto con esa etiqueta es el 22. Si se solicita al daemon que se asocie al puerto 2222, el kernel comprueba la etiqueta, encuentra el tipo genérico que la política asignó a ese número y rechaza el permiso name_bind en el socket.

Por eso este fallo no parece un problema del firewall. El kernel rechaza la operación antes de que exista un socket en escucha, de modo que sshd informa del error y termina. Un problema del firewall es lo contrario: el daemon está activo y funciona correctamente, pero los paquetes se descartan al entrar.

getenforce indica en qué modo se encuentra el sistema. En Permissive se registra una denegación, pero no se aplica, por lo que el cambio de puerto parece funcionar y falla cuando alguien ejecuta setenforce 1 o el sistema se reinicia en modo enforcing. Etiquete el puerto en cualquier caso. La guía básica de SELinux para servidores explica correctamente los modos, los contextos y los booleanos.

Paso 3: establezca el puerto en la configuración de sshd

En Rocky Linux 9 y 10, AlmaLinux 9 y 10, y las versiones actuales de Fedora, /etc/ssh/sshd_config comienza con una línea de inclusión, por lo que el lugar adecuado para este cambio es un archivo drop-in. Las actualizaciones de paquetes no entrarán en conflicto con su modificación.

grep -n '^Include' /etc/ssh/sshd_config
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/10-port.conf
sudo sshd -t

Si grep no encuentra ninguna línea Include, como ocurre en Rocky Linux 8 y otras imágenes antiguas, añada Port 2222 directamente a /etc/ssh/sshd_config. sshd -t analiza toda la configuración, incluidos los archivos drop-in, e informa de los errores de sintaxis. Corrija todos los errores que informe antes de reiniciar, porque una configuración que no se puede analizar impide que el daemon vuelva a iniciarse.

Port puede aparecer más de una vez, y sshd escucha en todos los puertos indicados. Mantener Port 22 junto con Port 2222 durante el primer día es una medida de seguridad sencilla, siempre que recuerde eliminarlo.

¿sshd se inicia mediante una unidad de socket?

Algunas imágenes inician SSH mediante la activación de sockets de systemd en lugar de ejecutarlo como un servicio de larga duración. Cuando está configurado de esta forma, systemd controla el socket de escucha y entrega las conexiones a sshd, por lo que la línea Port de sshd_config se ignora por completo. Compruébelo antes de reiniciar nada:

systemctl is-enabled sshd.socket

Una respuesta enabled significa que el puerto está definido en la unidad de socket, no en sshd_config:

sudo systemctl edit sshd.socket
[Socket]
ListenStream=
ListenStream=2222

Se necesita el ListenStream= sin argumentos. Los valores se acumulan en los archivos drop-in. Sin una asignación vacía que borre primero la lista, el socket seguirá escuchando en 22 además de 2222. Aplíquelo con sudo systemctl daemon-reload y después con sudo systemctl restart sshd.socket. Si la unidad está deshabilitada o no existe en su servidor, esta sección no se aplica.

Paso 4: reinicie y pruebe desde una segunda terminal

sudo systemctl restart sshd
systemctl status sshd
sudo ss -tlnp | grep sshd

Mantenga esta terminal abierta. No cierre la sesión. Abra una segunda terminal en su equipo y conéctese al nuevo puerto:

ssh -p 2222 youruser@203.0.113.10

Cierre la primera sesión sólo después de que el segundo inicio de sesión haya funcionado. Si no funciona, todavía tendrá un shell desde el que podrá deshacer todos los cambios. Este hábito marca la diferencia entre un cambio de cinco minutos y pasar toda la tarde en la consola del proveedor.

¿Firewall bloqueando o denegación de SELinux? Cómo distinguirlos

Desde el portátil, los dos fallos parecen casi idénticos. En el servidor no se parecen en nada.

  • Si systemctl status sshd muestra que la unidad ha fallado, el daemon nunca obtuvo su socket. Se trata de un error de configuración o de una denegación de SELinux.
  • Si la unidad está activa y ss -tlnp muestra que sshd está enlazado al puerto nuevo, el daemon funciona y el problema está en la ruta de red: firewalld, el firewall independiente del proveedor o la dirección y el puerto utilizados.

Para el caso de SELinux, lea el registro de auditoría en lugar de hacer suposiciones:

sudo ausearch -m AVC -ts recent
sudo journalctl -u sshd -n 50 --no-pager

Una denegación de name_bind en la clase tcp_socket indica el proceso en comm="sshd", el número de puerto en src= y la etiqueta que tiene realmente el puerto en tcontext=. Este último campo contiene la respuesta. Cualquier valor distinto de ssh_port_t significa que el paso 2 no se aplicó al puerto utilizado. Normalmente, se debe a un error tipográfico en el número o al protocolo incorrecto. Instale setroubleshoot-server si prefiere que sealert convierta el registro en una frase.

El mensaje que escribe el propio sshd cuando el kernel rechaza el enlace tiene este formato:

error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.

Permission denied en un puerto superior a 1024, donde no se necesitan privilegios de root para enlazarlo, es la firma de SELinux. Address already in use en esa misma línea indica un fallo diferente: otro proceso está usando el puerto. Desde el cliente, la diferencia entre conexión rechazada y conexión agotada por tiempo permite distinguir los dos casos de red, porque un rechazo significa que el paquete llegó al host y no había ningún proceso escuchando, mientras que un tiempo de espera agotado significa que no respondió nada.

Cierre el puerto 22 y actualice los clientes

Después de comprobar que varios inicios de sesión en el nuevo puerto funcionan, retire el puerto 22:

sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

No modifique la etiqueta de SELinux del puerto 22. Procede de la política base y no concede acceso cuando el firewall deja de aceptar paquetes entrantes.

Después, actualice los clientes, porque debe indicar el puerto a todas las herramientas que daban por supuesto el puerto predeterminado. Configúrelo una vez en ~/.ssh/config en su propio equipo, en lugar de escribir -p continuamente:

Host myvps
  HostName 203.0.113.10
  Port 2222
  User youruser

scp, sftp, rsync y Ansible leen ese archivo. Los trabajos de copia de seguridad, las comprobaciones de monitorización y los scripts de cron que tienen el puerto 22 escrito directamente no lo leen. Localícelos mientras el cambio todavía está reciente.

Qué consigue y qué no consigue cambiar el puerto

Reduce el ruido de los registros. Los escáneres automatizados atacan constantemente el puerto 22. Al dejar de usarlo, la mayoría de esas líneas desaparecen del journal y resulta más fácil ver los eventos reales. No es un control de seguridad. Cualquier escáner que recorra todo el rango de puertos encuentra el daemon y lee igualmente su banner de versión. Trate el cambio de puerto como una tarea de mantenimiento. Aplique la protección real mediante autenticación exclusiva con claves y desactive los inicios de sesión con contraseña. La guía de refuerzo de SSH para un VPS explica este proceso paso a paso.

Todo lo anterior funciona de la misma forma en las dos principales reconstrucciones de RHEL, porque se generan a partir de las mismas fuentes. Consulte Comparación entre Rocky Linux y AlmaLinux si todavía está decidiendo cuál usar. Compruebe qué versión recibió realmente antes de seguir una guía antigua, mediante cat /etc/os-release. Las guías escritas para Rocky Linux 8 siguen apareciendo en buenas posiciones y sus pasos semanage y firewall-cmd siguen siendo correctos. Sin embargo, Rocky 8 no tiene la línea include sshd_config.d ni una unidad de socket que deba tener en cuenta. Por tanto, la parte de sshd de esas guías no coincide con un sistema actual.

hay que indicar a fail2ban el nuevo puerto

fail2ban no está disponible en los repositorios base. Se obtiene desde EPEL (paquetes adicionales para Enterprise Linux):

sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalld

El subpaquete fail2ban-firewalld hace que fail2ban aplique los bloqueos mediante firewalld. Es lo adecuado en un sistema donde firewalld administra el conjunto de reglas.

La jaula incluida sshd establece port = ssh, y ese nombre se resuelve mediante /etc/services en el puerto 22. Después del cambio, la jaula supervisa un puerto que nadie está atacando. Por eso no bloquea a nadie, mientras los intentos de inicio de sesión fallidos se acumulan en el puerto 2222. Establezca el puerto por número en /etc/fail2ban/jail.local:

[sshd]
enabled = true
port = 2222
backend = systemd
maxretry = 5
bantime = 3600

backend = systemd lee los fallos del journal en lugar de /var/log/secure. Es la opción más segura en una instalación mínima donde rsyslog puede no estar disponible. Inícielo con sudo systemctl enable --now fail2ban y compruebe la jaula con sudo fail2ban-client status sshd. La sintaxis de la jaula es la misma que se usa en la configuración de fail2ban para SSH en Ubuntu 24.04. Sólo difieren el origen del paquete y la acción de bloqueo.

Los parches importan más que el puerto

Un servidor con el puerto SSH cambiado y cuatro meses de actualizaciones de seguridad sin aplicar está en peor estado que uno que usa el puerto 22 y se actualiza automáticamente cada noche. Active las actualizaciones desatendidas en la misma sesión, mientras ya tiene una cuenta root: actualizaciones automáticas de dnf en Rocky Linux y AlmaLinux explica cómo configurar el temporizador y elegir entre descargar las actualizaciones o aplicarlas.

FAQ

¿Por qué sshd no inicia después de cambiar el puerto en Rocky Linux?

Casi siempre falta la etiqueta de puerto de SELinux. sshd se ejecuta confinado en el dominio sshd_t, y la política sólo le permite asociarse a puertos etiquetados como ssh_port_t, que de forma predeterminada sólo incluye el puerto 22. El kernel rechaza la asociación, por lo que el daemon termina en lugar de escuchar, y journalctl -u sshd contiene una línea con el formato error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.. Ejecute sudo semanage port -a -t ssh_port_t -p tcp 2222 con su propio número de puerto y reinicie el servicio. Si no se encuentra semanage, instale primero policycoreutils-python-utils.

¿Sigo necesitando semanage si SELinux está en modo permisivo?

Sí. En modo permisivo, la denegación se registra y la asociación se permite de todos modos, por lo que parece que el cambio ha funcionado. La etiqueta sigue faltando. En cuanto alguien ejecute setenforce 1, o el equipo arranque con SELINUX=enforcing en /etc/selinux/config, sshd dejará de iniciar en ese puerto. Añadir la etiqueta requiere un comando y elimina un fallo que, de otro modo, podría aparecer semanas después sin una causa evidente.

El puerto está etiquetado y sshd se está ejecutando. Entonces, ¿por qué se agota el tiempo de espera de mi conexión?

Un daemon en ejecución indica que SELinux está satisfecho, por lo que el paquete se está descartando durante la entrada. Compruebe sudo firewall-cmd --list-ports para ver su puerto y confirme que ejecutó firewall-cmd --reload después de la regla --permanent, porque una regla permanente por sí sola nunca se aplica al firewall en ejecución. Después, revise el panel de control de su proveedor para comprobar si hay un firewall de red independiente delante del VPS. Ese es el segundo punto donde suelen bloquearse las conexiones, y nada dentro del sistema operativo lo mostrará.

¿Qué puerto debería usar en lugar del 22?

Cualquier puerto TCP libre entre 1024 y 65535. Evite 2222 y 22222 en un servidor real, porque los escáneres los prueban inmediatamente después del 22. Confirme que el número está libre con sudo ss -tlnp, compruebe que la política de SELinux no lo haya asignado ya con sudo semanage port -l y evite cualquier puerto asignado a un servicio que pueda instalar más adelante. Un número alto y difícil de recordar es válido, porque lo escribirá una vez en ~/.ssh/config y no volverá a introducirlo manualmente.