Un servidor recién creado y expuesto a Internet empieza a recibir intentos de acceso por SSH en cuestión de minutos. El hardening consiste en reducir la superficie de ataque y dejar rastro de lo que ocurre: menos servicios expuestos, accesos solo con clave, parches al día y registro de los cambios sensibles. En este tutorial aplicarás esas medidas a un servidor Ubuntu 24.04 en un orden seguro, comprobando cada una antes de pasar a la siguiente, y terminarás con una auditoría de Lynis para ver qué queda por mejorar.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS recién instalado, por ejemplo un VPS de CubePath, y su dirección IP (
your_server_ip). - Acceso como
rooto con un usuario consudo. - Un equipo local con cliente SSH (Linux, macOS o Windows 10/11 con OpenSSH).
- Acceso a la consola del servidor desde el panel de tu proveedor, por si te quedas fuera por SSH mientras cambias su configuración.
Importantemientras modificas SSH o el firewall, mantén siempre abierta una sesión SSH ya iniciada y prueba los cambios desde una segunda terminal. Si algo falla, la sesión abierta te permite deshacerlo.
Paso 1: Actualizar el sistema
Muchas intrusiones aprovechan vulnerabilidades ya corregidas. Antes de nada, instala todas las actualizaciones pendientes:
sudo apt update
sudo apt full-upgrade -y
Si se ha actualizado el kernel, el sistema lo indica con el archivo /var/run/reboot-required. Comprueba si existe y reinicia en ese caso:
[ -f /var/run/reboot-required ] && echo "Reinicio necesario" || echo "No hace falta reiniciar"
sudo reboot
Paso 2: Crear un usuario administrador
Trabajar directamente como root hace que cualquier error o credencial robada tenga el máximo impacto. Crea un usuario propio (sustituye your_user por el nombre que quieras) y añádelo al grupo sudo:
sudo adduser your_user
sudo usermod -aG sudo your_user
adduser te pedirá una contraseña. Úsala solo para sudo; el acceso por SSH será con clave. Comprueba que el usuario tiene permisos de administración:
sudo -l -U your_user
User your_user may run the following commands on server:
(ALL : ALL) ALL
Paso 3: Configurar el acceso SSH con clave
Las claves SSH no se pueden adivinar por fuerza bruta como una contraseña. Desde tu equipo local, genera una clave Ed25519 si todavía no tienes una:
ssh-keygen -t ed25519 -C "your_user@portatil"
Copia la clave pública al servidor. ssh-copy-id la añade a ~/.ssh/authorized_keys del usuario con los permisos correctos:
ssh-copy-id your_user@your_server_ip
Abre una nueva terminal y comprueba que entras con la clave, sin que te pida la contraseña del usuario:
ssh your_user@your_server_ip
No sigas al paso siguiente hasta que este acceso funcione.
Paso 4: Endurecer la configuración de SSH
En Ubuntu 24.04, /etc/ssh/sshd_config incluye al principio todos los archivos /etc/ssh/sshd_config.d/*.conf, en orden alfabético, y para cada opción sshd se queda con el primer valor que encuentra. Algunas imágenes cloud crean 50-cloud-init.conf con PasswordAuthentication yes, así que tu archivo debe tener un nombre que se ordene antes, como 00-hardening.conf:
sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowUsers your_user
Qué hace cada opción:
PermitRootLogin no: nadie puede entrar directamente comoroot.PasswordAuthentication noyKbdInteractiveAuthentication no: desactivan el acceso con contraseña, solo se aceptan claves.MaxAuthTries 3yLoginGraceTime 30: menos intentos por conexión y menos tiempo para autenticarse.X11Forwarding no: un servidor no necesita reenviar aplicaciones gráficas.AllowUsers your_user: solo los usuarios de la lista pueden iniciar sesión por SSH. Añade más nombres separados por espacios si hace falta.
Valida la sintaxis antes de aplicar nada. Si no hay errores, el comando no muestra nada:
sudo sshd -t
Comprueba los valores efectivos, que confirman que ningún otro archivo los está pisando:
sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|maxauthtries|allowusers)'
permitrootlogin no
maxauthtries 3
kbdinteractiveauthentication no
passwordauthentication no
allowusers your_user
Aplica los cambios reiniciando el servicio, que en Ubuntu se llama ssh:
sudo systemctl restart ssh
Desde una segunda terminal, verifica que sigues entrando con tu usuario y que root ya no puede:
ssh your_user@your_server_ip
ssh root@your_server_ip
root@your_server_ip: Permission denied (publickey).
Paso 5: Activar el firewall con UFW
UFW viene instalado en Ubuntu, pero desactivado. La política recomendada es denegar todo el tráfico entrante y permitir solo lo que usas. Permite SSH primero, para no cortar tu propia conexión. La regla limit permite SSH pero bloquea temporalmente una IP que abra 6 o más conexiones en 30 segundos:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw limit OpenSSH
Si el servidor va a servir web, abre también HTTP y HTTPS:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Activa el firewall (responde y al aviso de que puede cortar conexiones SSH; la regla anterior mantiene la tuya) y revisa las reglas:
sudo ufw enable
sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (OpenSSH) LIMIT IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (OpenSSH (v6)) LIMIT IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
Notasi usas Docker, los puertos que publica un contenedor con
-pno pasan por las reglas de UFW. Publica solo lo necesario o enlázalo a127.0.0.1.
Paso 6: Instalar parches de seguridad automáticamente
unattended-upgrades instala cada día las actualizaciones del repositorio de seguridad de Ubuntu. Viene preinstalado en Ubuntu Server; instálalo por si acaso y actívalo:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Responde Yes en la pantalla que aparece. Comprueba que ha quedado activado:
cat /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
Las actualizaciones del kernel solo se aplican al reiniciar. Si aceptas reinicios automáticos en una ventana de poco tráfico, añádelo en un archivo propio para no modificar el del paquete:
sudo nano /etc/apt/apt.conf.d/52unattended-upgrades-local
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
Haz una simulación para confirmar que la configuración es válida:
sudo unattended-upgrade --dry-run --debug 2>&1 | tail -5
Los resultados de cada ejecución quedan en /var/log/unattended-upgrades/unattended-upgrades.log.
Paso 7: Revisar los servicios expuestos
Cada puerto abierto es una posible entrada. Lista los procesos que escuchan en la red:
sudo ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=512,fd=16))
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=512,fd=14))
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=512,fd=15))
tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=801,fd=3),("systemd",pid=1,fd=100))
Lo que escucha en 127.0.0.x solo es accesible desde el propio servidor. Revisa cualquier servicio en 0.0.0.0 o [::] que no reconozcas. Para ver qué servicios arrancan con el sistema:
systemctl list-unit-files --type=service --state=enabled
Si encuentras uno que no usas, detenlo y desactívalo (sustituye nombre_del_servicio), o desinstala directamente el paquete:
sudo systemctl disable --now nombre_del_servicio
Paso 8: Ajustar parámetros de red y del kernel
Algunos parámetros del kernel reducen la información expuesta y la exposición a ataques de red sencillos. Ubuntu ya trae valores seguros para varios de ellos (como tcp_syncookies o dmesg_restrict); este archivo los fija explícitamente y añade los que faltan:
sudo nano /etc/sysctl.d/99-hardening.conf
# No aceptar ni enviar redirecciones ICMP
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Rechazar paquetes con enrutamiento de origen
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Registrar paquetes con direcciones imposibles
net.ipv4.conf.all.log_martians = 1
# Protección frente a SYN flood
net.ipv4.tcp_syncookies = 1
# Ocultar direcciones del kernel y el buffer de dmesg a usuarios sin privilegios
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
Advertenciasi el servidor actúa como router, VPN o nodo de Kubernetes, revisa estos valores antes de aplicarlos. Este archivo no toca
ip_forward, que Docker y otras herramientas activan cuando lo necesitan.
Carga todos los archivos de /etc/sysctl.d/ y comprueba un par de valores:
sudo sysctl --system > /dev/null
sysctl net.ipv4.conf.all.accept_redirects kernel.kptr_restrict
net.ipv4.conf.all.accept_redirects = 0
kernel.kptr_restrict = 2
Paso 9: Registrar cambios sensibles con auditd
auditd registra a nivel de kernel quién modifica archivos críticos, incluso si luego se borran los logs de la aplicación. Instálalo:
sudo apt install auditd
Crea un archivo de reglas que vigile usuarios, grupos, sudo y la configuración de SSH. La opción -p wa registra escrituras y cambios de atributos, y -k asigna una etiqueta para buscar después:
sudo nano /etc/audit/rules.d/50-hardening.rules
-w /etc/passwd -p wa -k identidad
-w /etc/shadow -p wa -k identidad
-w /etc/group -p wa -k identidad
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d/ -p wa -k sshd
Carga las reglas y compruébalas:
sudo augenrules --load
sudo auditctl -l
-w /etc/passwd -p wa -k identidad
-w /etc/shadow -p wa -k identidad
-w /etc/group -p wa -k identidad
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d -p wa -k sudoers
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d -p wa -k sshd
Pruébalo creando y borrando un usuario de prueba, y busca los eventos con la etiqueta identidad:
sudo useradd prueba-audit && sudo userdel prueba-audit
sudo ausearch -k identidad -i --start today | tail -5
Verás entradas con el comando ejecutado (comm=useradd) y el usuario que lo lanzó (auid=your_user).
Paso 10: Comprobar AppArmor y bloquear ataques de fuerza bruta
Ubuntu activa AppArmor por defecto, que limita qué puede hacer cada programa con perfil aunque sea comprometido. Confirma que está cargado:
sudo aa-status | head -3
apparmor module is loaded.
120 profiles are loaded.
48 profiles are in enforce mode.
Con SSH limitado a claves, los intentos de fuerza bruta ya no pueden tener éxito, pero siguen llenando los logs y consumiendo recursos. Fail2Ban bloquea en el firewall las IP que acumulan fallos. Instálalo; en Ubuntu la jaula de SSH viene activada:
sudo apt install fail2ban
sudo fail2ban-client status sshd
La guía de Fail2Ban de esta misma sección explica cómo ajustar tiempos de bloqueo, listas blancas y jaulas para otros servicios.
Paso 11: Auditar el resultado con Lynis
Lynis revisa cientos de puntos de configuración y te da una lista priorizada de sugerencias. Instálalo desde los repositorios de Ubuntu y lanza una auditoría:
sudo apt install lynis
sudo lynis audit system
Al final del informe verás el índice de hardening y las rutas de los resultados:
Hardening index : 72 [############## ]
Tests performed : 262
...
- Test and debug information : /var/log/lynis.log
- Report data : /var/log/lynis-report.dat
Revisa la sección Suggestions del informe. No todas aplican a cada servidor (por ejemplo, las que piden particiones separadas); prioriza las que afectan a servicios expuestos y a cuentas de usuario. Vuelve a ejecutar Lynis tras cada cambio importante para comparar el índice.
Solución de problemas
- Te has quedado fuera por SSH: entra por la consola web del panel, revisa
/etc/ssh/sshd_config.d/00-hardening.conf(normalmente unAllowUserscon un nombre mal escrito) y ejecutasudo sshd -t && sudo systemctl restart ssh. - SSH sigue aceptando contraseñas: algún archivo de
/etc/ssh/sshd_config.d/con un nombre anterior al tuyo en orden alfabético definePasswordAuthentication yes. Localízalo congrep -ri passwordauthentication /etc/ssh/sshd_config /etc/ssh/sshd_config.d/. - Un servicio deja de responder tras activar UFW: falta la regla de su puerto. Añádela con
sudo ufw allow puerto/tcpy compruébalo consudo ufw status numbered.
Conclusión
Tu servidor Ubuntu 24.04 ya solo acepta acceso SSH con clave y sin root, filtra el tráfico entrante con UFW, instala parches de seguridad por sí mismo, expone únicamente los servicios necesarios y registra los cambios en usuarios, sudo y SSH. El hardening no es una tarea única: repítelo con cada servicio nuevo que instales.
Como siguientes pasos puedes:
- Ajustar Fail2Ban con tiempos de bloqueo progresivos y jaulas para tus aplicaciones web.
- Configurar copias de seguridad automáticas y comprobar que sabes restaurarlas.
- Centralizar los logs y los eventos de auditd en otro servidor para que un atacante no pueda borrarlos.
