Las formas de este mensaje
kex_exchange_identification: read: Connection reset by peer
Connection reset by 203.0.113.10 port 22
kex_exchange_identification: Connection closed by remote host
Connection closed by 203.0.113.10 port 22
Los clientes recientes pueden mostrar solo la última línea, Connection closed by 203.0.113.10 port 22, salvo que añadas -v. Reset y closed solo se diferencian en cómo terminó la conexión. Trátalos como el mismo problema, porque la misma causa puede mostrar uno u otro según lo que haya por en medio.
Empieza aquí
ssh -v user@server true
Esta línea de la salida es una pista muy útil:
debug1: kex_exchange_identification: banner line 0: Not allowed at this time
Ese texto procede del propio sshd. Significa que el servidor está en marcha y te descarta a propósito, así que ve a la causa 1 y a la causa 2. Para leer el motivo, usa una consola u otra conexión al servidor:
sudo journalctl -u ssh -u sshd --since "1 hour ago" | grep -iE 'maxstartups|penalty'
Si estás bloqueado, prueba también desde otra red, como el punto de acceso del móvil. Si así funciona, el bloqueo está ligado a tu dirección.
Causa 1: penalizaciones de sshd
Desde OpenSSH 9.8, sshd penaliza las direcciones que fallan al iniciar sesión, y viene activado por defecto. Mientras dura la penalización, se descartan las conexiones nuevas de esa dirección. El log del servidor muestra:
drop connection #0 from [203.0.113.10]:41056 on [203.0.113.20]:22 penalty: failed authentication
Basta con esperar: el máximo por defecto es de 10 minutos. Es más probable que te afecte detrás de una dirección de oficina compartida, o con un script o una tarea de monitorización que sigue fallando, así que arregla primero lo que falla. Para una dirección de confianza, añade esto a sshd_config:
PerSourcePenaltyExemptList 203.0.113.10
Un cliente que ofrece muchas claves puede fallar varias veces en un solo acceso. Mira Too many authentication failures para limitarlo a la clave correcta.
Causa 2: MaxStartups
MaxStartups limita las conexiones que aún no han iniciado sesión. El valor por defecto es 10:30:100: a partir de 10 conexiones así, sshd descarta las nuevas al azar con un 30 % de probabilidad, que sube hasta descartarlas todas al llegar a 100. Los bots que escanean un servidor público pueden llenar este límite. El log muestra:
drop connection #1 from [203.0.113.10]:37954 on [203.0.113.20]:22 Maxstartups
Las versiones antiguas registran exceeded MaxStartups. Comprueba el ajuste y las conexiones actuales:
sudo sshd -T | grep -iE '^(maxstartups|persourcemaxstartups|logingracetime)'
ss -tn state established '( sport = :22 )'
El fallo suele ser intermitente: un reintento funciona. Para dejar sitio, sube el límite y reduce el tráfico de bots con una lista de direcciones permitidas en el firewall o un LoginGraceTime más corto:
MaxStartups 30:30:100
Valida y aplica. El servicio se llama ssh en Debian y Ubuntu, y sshd en los sistemas de tipo Red Hat:
sudo sshd -t && sudo systemctl reload ssh
Causa 3: TCP wrappers
OpenSSH upstream abandonó esta función hace tiempo, pero algunas distribuciones todavía la compilan. Debian 13 lo hace, y una línea sshd: ALL en /etc/hosts.deny produjo el mensaje de reset en nuestra prueba. Desde OpenSSH 9.8 la biblioteca está enlazada a sshd-session, no a sshd, así que comprueba los dos:
ldd /usr/sbin/sshd /usr/lib/openssh/sshd-session 2>/dev/null | grep libwrap
grep -v '^#' /etc/hosts.deny /etc/hosts.allow
Quita la regla, o permite tu dirección en /etc/hosts.allow:
sshd: 203.0.113.10
Causa 4: un firewall o fail2ban
Un firewall, un balanceador de carga o un dispositivo de prevención de intrusiones que envía un reset TCP después de abrir la conexión da esta familia de mensajes. Lo reprodujimos con esta regla, con la que SSH mostró Connection reset by peer:
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate ESTABLISHED -j REJECT --reject-with tcp-reset
fail2ban es una causa menos probable de este mensaje de lo que se suele pensar. Sus acciones por defecto rechazan conexiones nuevas, lo que el cliente informa como Connection refused, no como un reset. Aun así merece la pena mirarlo si fallaste varios inicios de sesión:
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 203.0.113.10
Consulta fail2ban para SSH para más información.
Causa 5: un túnel sin salida
Si te conectas a través de un túnel o un reenvío de puertos, el primer salto acepta tu conexión y luego no consigue llegar al destino real. El cliente ve el reset. Con ssh -L, la terminal que ejecuta el túnel muestra el motivo verdadero:
channel 3: open failed: connect failed: Connection refused
Mira allí, o en el log de tu proxy. Comprueba que la dirección y el puerto de destino son correctos y que sshd está en marcha en el destino.
Causa 6: el propio sshd tiene un problema
Cuando los casos anteriores no encajan, prueba la configuración y ejecuta una copia en modo depuración en un puerto libre. Tu servicio normal sigue funcionando:
sudo sshd -t
sudo /usr/sbin/sshd -d -p 2200
Después conéctate con ssh -p 2200 user@server y lee lo que muestra la copia de depuración. Permite antes ese puerto en tu firewall y ciérralo después.
Preguntas
¿Qué significa kex_exchange_identification: Connection reset by peer?
La conexión TCP se abrió pero se cortó antes del saludo SSH. El servidor, o algo en medio, te rechazó antes de comprobar ninguna clave ni contraseña.
¿Cuánto dura una penalización de sshd?
Desde OpenSSH 9.8 las penalizaciones crecen con los fallos repetidos, hasta 10 minutos por defecto. Basta con esperar, y PerSourcePenaltyExemptList exime a las direcciones de confianza.
¿Por qué el corte ocurre solo a veces?
Un corte intermitente suele apuntar a MaxStartups: cuando hay demasiadas conexiones todavía iniciando sesión, sshd descarta las nuevas al azar.
Fuentes
- sshd_config(5), MaxStartups y PerSourcePenalties
- Notas de la versión OpenSSH 9.8
- sshd(8), manual de OpenBSD
- hosts_access(5), manual de Debian