
Hacer un seguimiento:Parece que la rápida serie de desconexiones que coinciden con unos pocos meses de funcionamiento de cada servidor probablemente sea una coincidencia y solo sirvió para revelar el problema real. Es casi seguro que la razón por la que no pudo volver a conectarse se debe a los valores de AliveInterval (respuesta de Kasperd). El uso de la opción ExitOnForwardFailure debería permitir que el tiempo de espera se agote correctamente antes de volver a conectarse, lo que debería resolver el problema en la mayoría de los casos. La sugerencia de MadHatter (el script de eliminación) es probablemente la mejor manera de asegurarse de que el túnel pueda volver a conectarse incluso si todo lo demás falla.
Tengo un servidor (A) detrás de un firewall que inicia un túnel inverso en varios puertos a un pequeño VPS DigitalOcean (B) para poder conectarme a A a través de la dirección IP de B. El túnel ha estado funcionando de manera constante durante aproximadamente 3 meses, pero repentinamente falló cuatro veces en las últimas 24 horas. Lo mismo sucedió hace un tiempo con otro proveedor de VPS: meses de funcionamiento perfecto y, de repente, múltiples fallos rápidos.
Tengo un script en la máquina A que ejecuta automáticamente el comando de túnel ( ssh -R *:X:localhost:X address_of_B
para cada puerto X) pero cuando se ejecuta, dice Warning: remote port forwarding failed for listen port X
.
Al ingresar al sshd /var/log/secure
en el servidor se muestran estos errores:
bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X
La solución requiere reiniciar el VPS. Hasta entonces, todos los intentos de volver a conectarse darán el mensaje "Error en el reenvío de puerto remoto" y no funcionarán. Ahora hemos llegado al punto en el que el túnel sólo dura unas 4 horas antes de detenerse.
Nada ha cambiado en el VPS, y es una máquina de un solo uso y un solo usuario que solo sirve como punto final del túnel inverso. Está ejecutando OpenSSH_5.3p1 en CentOS 6.5. Parece que sshd no cierra los puertos en su extremo cuando se pierde la conexión. No puedo explicar por qué, o por qué sucedería repentinamente ahora después de meses de funcionamiento casi perfecto.
Para aclarar, primero necesito descubrir por qué sshd se niega a escuchar en los puertos después de que falla el túnel, lo que parece deberse a que sshd deja los puertos abiertos y nunca los cierra. Ese parece ser el principal problema. Simplemente no estoy seguro de qué causaría que se comportara de esta manera después de meses de comportarse como esperaba (es decir, cerrar los puertos de inmediato y permitir que el script se vuelva a conectar).
Respuesta1
Estoy de acuerdo con MadHatter en que es probable que se trate de reenvíos de puertos de conexiones ssh inactivas. Incluso si su problema actual resulta ser otra cosa, tarde o temprano puede encontrarse con conexiones ssh inactivas.
Hay tres formas en que pueden ocurrir estas conexiones inactivas:
- Uno de los dos puntos finales se reinició mientras que el otro extremo de la conexión estaba completamente inactivo.
- Uno de los dos puntos finales cerró la conexión, pero en el momento en que se cerró la conexión, hubo una interrupción temporal en la conexión. La interrupción duró unos minutos después de que se cerró la conexión y, por lo tanto, el otro extremo nunca se enteró del cierre de la conexión.
- La conexión sigue siendo completamente funcional en ambos puntos finales de la conexión ssh, pero alguien colocó un dispositivo con estado en algún lugar entre ellos, lo que agotó el tiempo de espera de la conexión debido a la inactividad. Este dispositivo con estado sería un NAT o un firewall; el firewall que ya mencionaste es el principal sospechoso.
Averiguar cuál de los tres anteriores está sucediendo no es muy importante, porque existe un método que abordará los tres. Ese es el uso de mensajes keepalive.
Debe buscar la ClientAliveInterval
palabra clave for sshd_config
y el ServerAliveInterval
intervalo para ssh_config
o ~/.ssh/config
.
Ejecutar el ssh
comando en un bucle puede funcionar bien. También es una buena idea insertar una suspensión en el bucle para no terminar inundando el servidor cuando la conexión falla por algún motivo.
Si el cliente se vuelve a conectar antes de que la conexión haya terminado en el servidor, puede terminar en una situación en la que la nueva conexión ssh esté activa, pero no tenga reenvíos de puertos. Para evitarlo, debe utilizar la ExitOnForwardFailure
palabra clave en el lado del cliente.
Respuesta2
Para mí, cuando un ssh
túnel se desconecta, la conexión tarda un poco en restablecerse, por lo que el ssh
proceso continúa bloqueándose, dejándome sin túneles activos y no sé por qué. Una solución alternativa es poner ssh
en segundo plano -f
y generar nuevas conexiones sin esperar a que se restablezcan las conexiones antiguas. Se -o ExitOnForwardFailure=yes
puede utilizar para limitar el número de procesos nuevos. Esto -o ServerAliveInterval=60
mejora la confiabilidad de su conexión actual.
Puede repetir el ssh
comando con frecuencia, digamos, en un cron
, o en un bucle en su secuencia de comandos, por ejemplo, a continuación, ejecutamos el ssh
comando cada 3 minutos:
while (1)
do
ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
sleep 180
done
Respuesta3
Puede encontrar el proceso que vincula el puerto en ese servidor con
sudo netstat -apn|grep -w X
Parece muy probable que sea el medio desaparecido sshd
, pero ¿por qué hacer suposiciones cuando se pueden tener datos? También es una buena manera para que un script encuentre un PID al que enviar la señal 9 antes de intentar volver a abrir el túnel.
Respuesta4
En mi experiencia, ssh tiene la costumbre un poco molesta de no salir limpiamente si "algo" todavía se está ejecutando en el sistema remoto. Por ejemplo, comenzó en segundo plano. Puedes reproducir esto mediante:
ssh <server>
while true; do sleep 60; done&
exit
Su ssh cerrará la sesión, pero en realidad no cerrará la sesión, hasta que el proceso remoto salga (lo cual no sucederá, porque es un bucle "mientras es verdadero"). Puede ser que esté sucediendo algo similar: su sesión tiene un proceso "atascado" que está siendo generado por ssh. El puerto permanece en uso y, por lo tanto, su proceso local no puede reutilizarlo.