Hardening SSH en un VPS Linux: guia completa de sshd_config
Protege SSH en tu VPS con Debian 12 o Ubuntu 24.04. Generacion de claves Ed25519, hardening de sshd_config, configuracion de ProxyJump como bastion, cifrado reforzado y verificacion con ssh-audit. Cada cambio probado antes de continuar.
SSH es la puerta de entrada a tu servidor. Los bots automatizados empiezan a golpear el puerto 22 a los pocos minutos de que un VPS entra en linea. Esta guia recorre cada cambio de sshd_config necesario para proteger SSH en Debian 12 (OpenSSH 9.2) y Ubuntu 24.04 (OpenSSH 9.6), con un paso de verificacion despues de cada cambio para que sepas que realmente funciono.
Requisitos previos
Necesitas:
- Un VPS con Debian 12 o Ubuntu 24.04 (nuevo o existente)
- Un usuario no root con acceso sudo
- Una segunda terminal o sesion SSH abierta al servidor (la necesitaras para probar cambios sin quedarte fuera)
Esta guia forma parte de la serie Linux VPS Security: Threats, Layers, and Hardening Guide. Despues de proteger SSH aqui, configura la proteccion automatica contra fuerza bruta con .
Como genero una clave SSH segura para mi VPS?
Genera una clave Ed25519 en tu maquina local (tu portatil o estacion de trabajo, no el servidor). Ed25519 produce una clave de 256 bits que ofrece 128 bits de seguridad, equivalente a RSA-3072, siendo mas rapida de generar y verificar. Las firmas son deterministicas, asi que no dependen de un generador de numeros aleatorios en el momento de firmar. Esto elimina toda una clase de ataques de implementacion que afectan a RSA.
ssh-keygen -t ed25519 -C "yourname@yourmachine"
Veras una salida como esta:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/yourname/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/yourname/.ssh/id_ed25519
Your public key has been saved in /home/yourname/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:xR5xGk3TOs4mEfW8sBv7g7LkE2PLxYae2TqfGxpfM3Q yourname@yourmachine
Establece una passphrase (frase de paso). Si alguien roba tu fichero de clave privada, la passphrase es lo unico que se interpone entre esa persona y tus servidores.
Ed25519 vs RSA: que clave debo usar?
| Ed25519 | RSA-4096 | |
|---|---|---|
| Tamano de clave | 256 bits | 4096 bits |
| Fortaleza de seguridad | ~128 bits | ~140 bits |
| Generacion de clave | Instantanea | 1-5 segundos |
| Verificacion de firma | Mas rapida | Mas lenta |
| Tamano del fichero de clave privada | 464 bytes | ~3.3 KB |
| Dependencia de RNG al firmar | No (deterministico) | Si |
| Compatibilidad | OpenSSH 6.5+ (2014) | Universal |
Usa Ed25519 salvo que necesites conectar a sistemas con OpenSSH anterior a 6.5, algo raro en 2026.
Copia tu clave publica al servidor
Desde tu maquina local:
ssh-copy-id -i ~/.ssh/id_ed25519.pub youruser@your-server-ip
Si ssh-copy-id no esta disponible (algunas instalaciones de macOS), copia manualmente:
cat ~/.ssh/id_ed25519.pub | ssh youruser@your-server-ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Verifica: Inicia sesion desde una nueva terminal usando autenticacion por clave:
ssh -i ~/.ssh/id_ed25519 youruser@your-server-ip
Si obtienes un shell sin introducir la contrasena del servidor (solo la passphrase de tu clave), la autenticacion por clave funciona.
La directiva Include
Antes de editar sshd_config, ten en cuenta esto: tanto Debian 12 como Ubuntu 24.04 incluyen Include /etc/ssh/sshd_config.d/*.conf al principio de /etc/ssh/sshd_config. OpenSSH usa el primer valor que encuentra para la mayoria de directivas. Cualquier fichero .conf en sshd_config.d/ tiene prioridad sobre los ajustes del fichero principal.
Comprueba lo que ya esta configurado:
ls -la /etc/ssh/sshd_config.d/
En Ubuntu 24.04, normalmente encontraras 50-cloud-init.conf si cloud-init esta activo. Lee los ficheros existentes antes de hacer cambios:
cat /etc/ssh/sshd_config.d/*.conf 2>/dev/null
Vamos a colocar nuestro hardening en un unico fichero que se carga primero:
sudo touch /etc/ssh/sshd_config.d/00-hardening.conf
sudo chmod 600 /etc/ssh/sshd_config.d/00-hardening.conf
El prefijo 00- asegura que nuestro fichero se lee antes que otros snippets de configuracion. El chmod 600 restringe el acceso de lectura solo a root, ya que este fichero controla quien puede iniciar sesion.
Todos los cambios de sshd_config en esta guia van en /etc/ssh/sshd_config.d/00-hardening.conf salvo que se indique lo contrario.
Como desactivo la autenticacion por contrasena en SSH?
Desactivar la autenticacion por contrasena obliga a usar solo claves. Los ataques de fuerza bruta pierden sentido porque no hay contrasena que adivinar.
Abre el fichero de hardening:
sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
Anade:
PasswordAuthentication no
KbdInteractiveAuthentication no
KbdInteractiveAuthentication sustituye al obsoleto ChallengeResponseAuthentication en OpenSSH 9.x. Desactiva ambos para cerrar todas las vias de login basadas en contrasena.
Antes de reiniciar sshd, valida siempre la configuracion y manten tu sesion actual abierta.
sudo sshd -t
Si no hay salida, la configuracion es valida. Los errores se imprimen en la terminal.
Ahora reinicia sshd:
sudo systemctl restart sshd
Verifica desde una segunda terminal (no cierres tu sesion actual):
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no youruser@your-server-ip
Deberias ver:
youruser@your-server-ip: Permission denied (publickey).
Eso confirma que la autenticacion por contrasena esta desactivada. Fijate en que dice (publickey) como unico metodo permitido. Es exactamente lo que buscamos.
Ahora confirma que el login por clave sigue funcionando desde esa misma segunda terminal:
ssh youruser@your-server-ip
Si ambas pruebas pasan, la autenticacion por contrasena esta desactivada y el login por clave funciona. Si el login por clave falla, vuelve a tu primera sesion (que sigue abierta) y corrige la configuracion antes de quedarte fuera.
Como desactivo el login de root por SSH en Ubuntu y Debian?
El login directo de root por SSH debe estar desactivado. Incluso con autenticacion solo por clave, una clave comprometida de root da acceso total al sistema sin registro de quien inicio sesion. Usa un usuario normal con sudo en su lugar.
Anade a /etc/ssh/sshd_config.d/00-hardening.conf:
PermitRootLogin no
Valida y reinicia:
sudo sshd -t && sudo systemctl restart sshd
Verifica desde una segunda terminal:
ssh root@your-server-ip
Salida esperada:
root@your-server-ip: Permission denied (publickey).
Verifica que el ajuste se aplico con sshd -T (la T mayuscula muestra la configuracion activa):
sudo sshd -T | grep -i permitrootlogin
permitrootlogin no
Como restrinjo el acceso SSH a usuarios y grupos concretos?
AllowUsers y AllowGroups limitan el login SSH a una lista explicita. Cualquiera que no este en la lista es rechazado, aunque tenga claves validas. Es una red de seguridad contra despliegues accidentales de claves o usuarios nuevos creados por paquetes.
Anade a /etc/ssh/sshd_config.d/00-hardening.conf:
AllowUsers youruser
Sustituye youruser por tu nombre de usuario real. Para permitir varios usuarios:
AllowUsers youruser deployer
Alternativamente, usa acceso basado en grupo (mejor para equipos):
sudo groupadd sshusers
sudo usermod -aG sshusers youruser
Despues en la configuracion:
AllowGroups sshusers
Orden de procesamiento
OpenSSH evalua el acceso en este orden: DenyUsers, AllowUsers, DenyGroups, AllowGroups. Una denegacion en cualquier etapa bloquea al usuario. Si usas AllowUsers, solo los usuarios listados pueden iniciar sesion. Si usas AllowGroups, solo los miembros de los grupos listados pueden iniciar sesion. Puedes combinarlos, pero AllowUsers se evalua primero.
Valida y reinicia:
sudo sshd -t && sudo systemctl restart sshd
Verifica desde una segunda terminal:
ssh youruser@your-server-ip
Confirma que tu usuario puede seguir iniciando sesion. Despues verifica que un usuario no listado seria rechazado:
sudo sshd -T | grep -i allowusers
allowusers youruser
Que limites de sesion SSH debo configurar?
Estas directivas limitan los intentos de autenticacion, los tiempos de espera de conexion y las conexiones no autenticadas. Ralentizan los ataques de fuerza bruta y limpian sesiones inactivas.
Anade a /etc/ssh/sshd_config.d/00-hardening.conf:
MaxAuthTries 3
LoginGraceTime 20
MaxStartups 10:30:60
MaxSessions 3
ClientAliveInterval 300
ClientAliveCountMax 2
Esto es lo que hace cada ajuste:
| Directiva | Valor | Efecto |
|---|---|---|
| MaxAuthTries | 3 | Desconecta tras 3 intentos fallidos de autenticacion por conexion |
| LoginGraceTime | 20 | Da 20 segundos para autenticarse antes de desconectar |
| MaxStartups | 10:30:60 | Tras 10 conexiones no autenticadas, descarta aleatoriamente el 30% de las nuevas. A 60, descarta todas. |
| MaxSessions | 3 | Maximo 3 sesiones multiplexadas por conexion |
| ClientAliveInterval | 300 | Envia un paquete keepalive cada 300 segundos (5 minutos) |
| ClientAliveCountMax | 2 | Desconecta tras 2 respuestas keepalive sin recibir |
Calculo de ClientAliveInterval: El timeout real por inactividad es ClientAliveInterval x ClientAliveCountMax. Con estos valores: 300 x 2 = 600 segundos = 10 minutos. Una sesion inactiva se desconecta tras 10 minutos sin respuesta.
Valida y reinicia:
sudo sshd -t && sudo systemctl restart sshd
Verifica:
sudo sshd -T | grep -E "maxauthtries|logingracetime|maxstartups|maxsessions|clientaliveinterval|clientalivecountmax"
maxauthtries 3
logingracetime 20
maxstartups 10:30:60
maxsessions 3
clientaliveinterval 300
clientalivecountmax 2
Desactivar funciones de reenvio innecesarias
Las funciones de forwarding (reenvio) amplian la superficie de ataque de SSH. Desactiva todo lo que no uses activamente.
Anade a /etc/ssh/sshd_config.d/00-hardening.conf:
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
Valida y reinicia:
sudo sshd -t && sudo systemctl restart sshd
Verifica:
sudo sshd -T | grep -E "allowagentforwarding|allowtcpforwarding|x11forwarding|permittunnel"
allowagentforwarding no
allowtcpforwarding no
x11forwarding no
permittunnel no
Por que debo desactivar el agent forwarding de SSH?
El agent forwarding permite que un servidor remoto use tus claves SSH locales para autenticarse en otros servidores. Suena practico para saltar entre maquinas. El problema: cualquiera con root en ese servidor remoto puede secuestrar tu socket de agente y usar tus claves.
El escenario de ataque:
- Activas el agent forwarding y te conectas por SSH al Servidor A.
- OpenSSH crea un socket en
/tmp/ssh-XXXX/agent.YYYYen el Servidor A. - Un atacante con root en el Servidor A lee la variable de entorno
SSH_AUTH_SOCKde tu sesion. - El atacante se conecta a ese socket:
SSH_AUTH_SOCK=/tmp/ssh-XXXX/agent.YYYY ssh user@server-b. - El Servidor B ve una autenticacion valida usando tu clave. El atacante esta dentro.
El atacante nunca toco tu clave privada. Solo necesito root en el servidor intermedio mientras tu sesion estaba activa.
Usa ProxyJump en su lugar (siguiente seccion). Proporciona el mismo acceso multi-salto sin exponer tu socket de agente en ningun servidor intermedio.
Como configuro SSH ProxyJump para acceso a traves de un bastion host?
ProxyJump enruta tu conexion SSH a traves de un jump host (bastion) sin agent forwarding. Tus claves nunca salen de tu maquina local. La conexion esta cifrada de extremo a extremo: el bastion solo ve trafico cifrado pasando.
Uso por linea de comandos
ssh -J jumpuser@bastion.example.com targetuser@10.0.1.50
El flag -J le dice a SSH que se conecte primero al bastion y luego haga un tunel hasta el destino. Puedes encadenar varios saltos con comas:
ssh -J jump1@bastion1,jump2@bastion2 targetuser@10.0.1.50
Configuracion en el fichero SSH config
Para uso habitual, anade entradas en ~/.ssh/config de tu maquina local:
Host bastion
HostName bastion.example.com
User jumpuser
IdentityFile ~/.ssh/id_ed25519
Host internal-app
HostName 10.0.1.50
User appuser
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Host internal-db
HostName 10.0.2.100
User dbadmin
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Ahora conecta a los servidores internos directamente:
ssh internal-app
SSH gestiona el salto a traves del bastion automaticamente.
Hardening del servidor bastion
En el bastion host, restringe lo que los usuarios de salto pueden hacer. Anade al sshd_config del bastion:
Match User jumpuser
PermitTTY no
X11Forwarding no
PermitTunnel no
ForceCommand /usr/sbin/nologin
AllowTcpForwarding yes
Esto permite TCP forwarding (necesario para ProxyJump) pero impide que el usuario de salto obtenga un shell, ejecute comandos o use X11. Si el bastion se ve comprometido, el atacante obtiene una cuenta de solo reenvio sin acceso a shell.
Que cifrados y algoritmos de intercambio de claves SSH son seguros?
Las listas de cifrado por defecto de OpenSSH incluyen algoritmos mantenidos por compatibilidad hacia atras. Eliminar los debiles reduce la superficie de ataque. Estas recomendaciones son para OpenSSH 9.2+ (Debian 12) y 9.6+ (Ubuntu 24.04).
Primero, regenera las claves del host usando solo Ed25519 y elimina las claves DSA o ECDSA:
sudo rm -f /etc/ssh/ssh_host_*key*
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""
Mantenemos una clave RSA del host para clientes que no soporten Ed25519 (raro, pero evita bloqueos).
Despues, elimina los moduli Diffie-Hellman debiles (grupos menores de 3072 bits):
sudo awk '$5 >= 3071' /etc/ssh/moduli > /tmp/moduli.safe
sudo mv /tmp/moduli.safe /etc/ssh/moduli
sudo chown root:root /etc/ssh/moduli
sudo chmod 644 /etc/ssh/moduli
Anade a /etc/ssh/sshd_config.d/00-hardening.conf:
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
| Categoria | Algoritmos | Notas |
|---|---|---|
| Key exchange | sntrup761x25519, curve25519, DH group16/18 | sntrup761 es hibrido post-cuantico. curve25519 es el estandar actual. |
| Ciphers | ChaCha20-Poly1305, AES-256-GCM, AES-128-GCM, AES-CTR | ChaCha20 primero: mas rapido por software sin AES-NI. GCM es cifrado autenticado. |
| MACs | HMAC-SHA2 ETM, UMAC-128 ETM | Solo ETM (Encrypt-then-MAC). Los modos sin ETM son mas debiles. |
| Host keys | Ed25519, RSA (SHA-2) | Sin DSA (roto). Sin ECDSA (dudas sobre curvas NIST). |
Valida y reinicia:
sudo sshd -t && sudo systemctl restart sshd
Verifica desde una segunda terminal que puedes seguir conectando. Si tu cliente SSH no soporta ninguno de estos algoritmos (cliente muy antiguo), obtendras un error "no matching cipher". En ese caso, actualiza tu cliente o anade temporalmente el algoritmo necesario.
Configurar un banner de login
Oculta la informacion de version de SSH y muestra un aviso legal:
sudo nano /etc/ssh/banner.txt
Authorized access only. All activity is monitored and logged.
Mantenlo corto. Los banners largos con info del sistema ayudan a los atacantes a identificar tu SO.
Anade a /etc/ssh/sshd_config.d/00-hardening.conf:
Banner /etc/ssh/banner.txt
DebianBanner no
DebianBanner no elimina la cadena de version Debian/Ubuntu del banner del protocolo SSH. La divulgacion de version ayuda a los atacantes a apuntar a vulnerabilidades conocidas de tu build especifica de OpenSSH.
Valida y reinicia:
sudo sshd -t && sudo systemctl restart sshd
Verifica desde tu maquina local:
ssh -v youruser@your-server-ip 2>&1 | grep "banner"
Referencia completa de sshd_config con hardening
Aqui esta el fichero completo /etc/ssh/sshd_config.d/00-hardening.conf con todos los ajustes de esta guia:
# Authentication
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
# Access control
AllowUsers youruser
# Session limits
MaxAuthTries 3
LoginGraceTime 20
MaxStartups 10:30:60
MaxSessions 3
ClientAliveInterval 300
ClientAliveCountMax 2
# Forwarding restrictions
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
# Cryptography
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
# Banner
Banner /etc/ssh/banner.txt
DebianBanner no
# Logging
LogLevel VERBOSE
LogLevel VERBOSE registra detalles adicionales incluyendo las huellas de clave usadas para la autenticacion. Util para auditar quien inicio sesion con que clave.
Despues de escribir este fichero, valida siempre antes de reiniciar:
sudo sshd -t && sudo systemctl restart sshd
Comprueba la configuracion efectiva completa:
sudo sshd -T
Esto muestra todos los ajustes activos, incluidos los valores por defecto. Filtra con grep para comprobar valores concretos:
sudo sshd -T | grep -E "permitrootlogin|passwordauthentication|allowusers"
permitrootlogin no
passwordauthentication no
allowusers youruser
Como verifico mi hardening SSH con ssh-audit?
ssh-audit escanea tu servidor y califica cada algoritmo como bueno, advertencia o fallo. Ejecutalo despues del hardening para confirmar que todo pasa.
Instala en tu maquina local o en un servidor separado (no el objetivo):
pip3 install ssh-audit
O con apt en Debian/Ubuntu:
sudo apt update && sudo apt install -y ssh-audit
Escanea tu servidor:
ssh-audit your-server-ip
Con el hardening de esta guia, no deberias ver entradas [fail]. La salida comienza con la version de OpenSSH detectada, y luego lista cada categoria de algoritmo:
# general
(gen) banner: SSH-2.0-OpenSSH_9.6
(gen) software: OpenSSH 9.6
(gen) compression: enabled (zlib@openssh.com)
# key exchange algorithms
(kex) sntrup761x25519-sha512@openssh.com -- [info] available since OpenSSH 8.5
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4
...
# encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5
(enc) aes256-gcm@openssh.com -- [info] available since OpenSSH 6.2
...
Si ves entradas [fail], comprueba que tu 00-hardening.conf esta cargado (recuerda el orden de Include) y que ningun otro fichero en sshd_config.d/ esta sobreescribiendo tus ajustes.
ssh-audit tambien tiene guias de hardening integradas:
ssh-audit --list-hardening-guides
Solucion de problemas
Me he quedado fuera
Si no puedes conectar por SSH tras un cambio de configuracion:
- Usa la consola web de tu proveedor de VPS (KVM/VNC) para iniciar sesion directamente.
- Corrige
/etc/ssh/sshd_config.d/00-hardening.conf. - Ejecuta
sshd -tpara validar. - Reinicia:
systemctl restart sshd.
Por eso insistimos: nunca cierres tu sesion activa antes de probar desde una segunda terminal.
sshd no arranca tras un cambio de configuracion
sudo sshd -t
Esto imprime la linea exacta y el fichero con el error. Problemas habituales:
- Errata en el nombre de un algoritmo (no se permiten espacios en las listas separadas por comas)
- Directivas duplicadas en varios ficheros (revisa
sshd_config.d/y elsshd_configprincipal) AllowUserscon un nombre de usuario que no existe (sshd arranca, pero nadie puede iniciar sesion)
Conexion rechazada tras el hardening de cifrado
Tu cliente SSH local puede no soportar los cifrados que configuraste. Comprueba que cifrados soporta tu cliente:
ssh -Q cipher
Compara con la lista del servidor. Anade de nuevo el cifrado que tu cliente necesite, o actualiza tu cliente.
Comprobar los logs de SSH
sudo journalctl -u sshd -f
Observa los logs en tiempo real mientras intentas una conexion desde otra terminal. Los fallos de autenticacion, errores de configuracion y desconexiones aparecen aqui.
Verificar que fichero de configuracion establece una directiva
sudo sshd -T | grep passwordauthentication
Si el valor no coincide con lo que configuraste, otro fichero en sshd_config.d/ esta sobreescribiendo el tuyo. Los ficheros se cargan en orden alfabetico. Nuestro 00-hardening.conf se carga primero, asi que gana para la mayoria de directivas. Pero revisa si cloud-init u otras herramientas de gestion escriben sus propias configuraciones.
Lista de verificacion
Repasa esto tras completar todos los pasos de hardening:
- Autenticacion por contrasena desactivada:
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no youruser@serverdevuelve "Permission denied" - Login de root desactivado:
ssh root@serverdevuelve "Permission denied" - Autenticacion por clave funciona:
ssh youruser@serverte da un shell - AllowUsers activo:
sudo sshd -T | grep allowusersmuestra tu usuario - Limites de sesion configurados:
sudo sshd -T | grep maxauthtriesmuestra 3 - Forwarding desactivado:
sudo sshd -T | grep allowagentforwardingmuestra no - Solo cifrados fuertes:
ssh-audit server-ipno muestra entradas [fail] - Logs funcionando:
sudo journalctl -u sshd -n 20muestra entradas de autenticacion recientes
Despues de proteger SSH, configura para banear automaticamente las IPs que fallen la autenticacion. Para control de acceso SSH a nivel de red, consulta .
Copyright 2026 Virtua.Cloud. Todos los derechos reservados. Este contenido es una obra original del equipo de Virtua.Cloud. La reproduccion, republicacion o redistribucion sin permiso escrito esta prohibida.
¿Listo para probarlo?
Despliega tu propio servidor en segundos. Linux, Windows o FreeBSD.
Ver planes VPS