Rocky Linux 9 y AlmaLinux 9 son reconstrucciones compatibles con Red Hat Enterprise Linux 9 y los sustitutos habituales de CentOS Linux, que ya no recibe actualizaciones. En esta guía prepararás un servidor recién creado con la base de seguridad que necesita antes de alojar cualquier servicio: un usuario administrador en el grupo wheel, SSH solo con claves y sin login de root, firewalld con los mínimos puertos abiertos, SELinux activo, Fail2Ban contra ataques de fuerza bruta y actualizaciones de seguridad automáticas con dnf-automatic.
Requisitos previos
- Un servidor con Rocky Linux 9 (o AlmaLinux 9 / RHEL 9) recién instalado, por ejemplo un VPS de CubePath.
- Acceso como
rootpor SSH. - Una clave SSH en tu equipo local. Si no tienes una, créala con
ssh-keygen -t ed25519como se explica en la guía para conectarse a un servidor por SSH. - Acceso a la consola del panel de CubePath por si pierdes el acceso SSH durante los cambios.
Importantemantén abierta la sesión SSH con la que trabajas y prueba cada cambio de acceso desde una segunda terminal. Si algo falla, podrás deshacerlo desde la sesión original.
Paso 1: Actualizar el sistema
Conéctate como root y aplica todas las actualizaciones pendientes:
ssh root@your_server_ip
dnf upgrade --refresh -y
Comprueba si la actualización requiere reiniciar (por ejemplo, porque cambió el kernel o glibc):
dnf needs-restarting -r
Core libraries or services have been updated since boot-up:
* kernel
Reboot is required to fully utilize these updates.
Si ves ese aviso, reinicia con reboot y vuelve a conectarte. Si el subcomando no existe, instala dnf-plugins-core.
Paso 2: Crear un usuario administrador
En la familia RHEL, los miembros del grupo wheel pueden usar sudo sin configuración adicional. Crea el usuario (sustituye your_user), añádelo a wheel y asígnale una contraseña, que necesitará para sudo:
useradd -m -G wheel your_user
passwd your_user
Comprueba el resultado:
id your_user
uid=1000(your_user) gid=1000(your_user) groups=1000(your_user),10(wheel)
Paso 3: Dar acceso SSH con clave al nuevo usuario
Si ya entras como root con una clave, copia su authorized_keys al nuevo usuario y ajusta propietario y permisos:
mkdir -p /home/your_user/.ssh
cp /root/.ssh/authorized_keys /home/your_user/.ssh/
chown -R your_user:your_user /home/your_user/.ssh
chmod 700 /home/your_user/.ssh
chmod 600 /home/your_user/.ssh/authorized_keys
Con SELinux activo, los archivos también necesitan la etiqueta correcta (ssh_home_t). restorecon la aplica según la política:
restorecon -Rv /home/your_user/.ssh
Si entras como root con contraseña, ejecuta en su lugar ssh-copy-id your_user@your_server_ip desde tu equipo local; crea los archivos con permisos y etiquetas correctos.
Sin cerrar la sesión de root, abre otra terminal local y prueba el acceso y sudo:
ssh your_user@your_server_ip
sudo whoami
root
Continúa el resto de la guía con este usuario.
Paso 4: Endurecer la configuración de SSH
En Rocky Linux 9, /etc/ssh/sshd_config incluye al principio todos los archivos de /etc/ssh/sshd_config.d/. OpenSSH aplica el primer valor que encuentra para cada opción, así que un archivo con prefijo 00- tiene prioridad sobre 50-redhat.conf y sobre 50-cloud-init.conf si existe. Créalo:
sudo vi /etc/ssh/sshd_config.d/00-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
Valida la sintaxis (sin salida si es correcta) y revisa los valores efectivos:
sudo sshd -t
sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|maxauthtries)'
maxauthtries 3
permitrootlogin no
passwordauthentication no
kbdinteractiveauthentication no
Recarga el servicio. En la familia RHEL se llama sshd:
sudo systemctl reload sshd
Desde otra terminal, comprueba que tu usuario entra y que root queda rechazado:
ssh root@your_server_ip
root@your_server_ip: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
Paso 5: Configurar firewalld
firewalld es el firewall por defecto de Rocky Linux. Algunas imágenes cloud no lo incluyen; instálalo y actívalo si hace falta:
sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
Revisa qué permite la zona por defecto:
sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: cockpit dhcpv6-client ssh
ports:
protocols:
...
La zona public rechaza todo lo que no esté en services o ports. Si no usas Cockpit, cierra su puerto (9090):
sudo firewall-cmd --permanent --remove-service=cockpit
Para un servidor web, añade HTTP y HTTPS. Las reglas --permanent no se aplican hasta recargar:
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services
dhcpv6-client http https ssh
Paso 6: Mantener SELinux en modo enforcing
SELinux limita lo que puede hacer cada servicio aunque sea comprometido. Desactivarlo es el "arreglo" más extendido y también el peor: casi todos los problemas se resuelven con una etiqueta o un booleano. Comprueba el modo actual:
sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Si el modo es permissive o disabled, cambia SELINUX=enforcing en /etc/selinux/config y reinicia. Si venía de disabled, fuerza el reetiquetado del sistema de archivos antes de reiniciar con sudo touch /.autorelabel.
Instala las herramientas de gestión, que incluyen semanage (lo necesitarás, por ejemplo, para cambiar el puerto SSH):
sudo dnf install -y policycoreutils-python-utils
Cuando una aplicación falle por SELinux, busca los bloqueos recientes en el log de auditoría:
sudo ausearch -m AVC -ts recent
Paso 7: Instalar Fail2Ban
Fail2Ban no está en los repositorios base, sino en EPEL. Activa EPEL (en Rocky Linux el paquete epel-release está en el repositorio extras) e instala Fail2Ban junto con el módulo para leer el journal de systemd:
sudo dnf install -y epel-release
sudo dnf install -y fail2ban python3-systemd
El paquete fail2ban instala también fail2ban-firewalld, que hace que los bloqueos se apliquen mediante firewalld. Crea tu configuración en jail.local:
sudo vi /etc/fail2ban/jail.local
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1
[sshd]
enabled = true
backend = systemd
Activa el servicio y comprueba la jail:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
Para desbloquear una IP: sudo fail2ban-client set sshd unbanip 203.0.113.50.
Paso 8: Activar actualizaciones de seguridad automáticas
dnf-automatic descarga e instala actualizaciones mediante un temporizador de systemd. Instálalo:
sudo dnf install -y dnf-automatic
Edita su configuración para aplicar solo las actualizaciones marcadas como de seguridad:
sudo vi /etc/dnf/automatic.conf
En la sección [commands], deja estos valores:
[commands]
upgrade_type = security
download_updates = yes
apply_updates = yes
Activa el temporizador y comprueba cuándo se ejecutará:
sudo systemctl enable --now dnf-automatic.timer
systemctl list-timers dnf-automatic.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-09-25 06:34:12 UTC 14h left - - dnf-automatic.timer dnf-automatic.service
dnf-automatic no reinicia el servidor. Revisa de vez en cuando sudo dnf needs-restarting -r y programa los reinicios cuando convenga.
Paso 9: Zona horaria y sincronización de hora
Rocky Linux sincroniza la hora con chronyd. Ajusta la zona horaria y comprueba la sincronización:
sudo timedatectl set-timezone Europe/Madrid
chronyc tracking | grep -E 'Reference ID|Leap status'
Reference ID : A29FC87B (time.example.net)
Leap status : Normal
Si chronyc no responde, instala y activa el servicio con sudo dnf install -y chrony && sudo systemctl enable --now chronyd.
Paso 10: Revisar los servicios expuestos
Lista los puertos en escucha y el proceso que los abre:
sudo ss -tulpn
Solo deberían aparecer sshd en el puerto 22 y servicios ligados a 127.0.0.1. Desactiva lo que no uses, por ejemplo Cockpit si está instalado:
sudo systemctl disable --now cockpit.socket
Solución de problemas
Pierdes el acceso SSH. Entra por la consola del panel de CubePath, borra o corrige /etc/ssh/sshd_config.d/00-hardening.conf y ejecuta sudo systemctl reload sshd.
Permission denied (publickey) con permisos correctos. Suele ser la etiqueta SELinux de .ssh, sobre todo si copiaste los archivos con mv. Compruébala con ls -Z ~/.ssh y corrígela con restorecon -Rv ~/.ssh.
Un servicio no arranca o no responde tras instalarlo. Antes de tocar SELinux, revisa si hay bloqueos con sudo ausearch -m AVC -ts recent y si el puerto está abierto con sudo firewall-cmd --list-all.
Fail2Ban no bloquea nada. Comprueba que la jail lee el journal (Journal matches en la salida de fail2ban-client status sshd) y revisa sudo journalctl -u fail2ban -n 30.
Conclusión
Tu servidor Rocky Linux 9 tiene ahora un administrador sin privilegios de root, SSH solo con claves, firewalld con los puertos mínimos, SELinux protegiendo los servicios, Fail2Ban bloqueando ataques de fuerza bruta y parches de seguridad automáticos. Como siguientes pasos, puedes cambiar el puerto SSH por defecto (recuerda registrarlo en SELinux con semanage), revisar la gestión de usuarios y permisos en Linux y configurar copias de seguridad.
