Seguimiento: Parece que la serie rápida de desconexiones que coinciden con unos pocos meses de ejecución de cada servidor probablemente sea una coincidencia y solo sirvió para revelar el problema real. La razón por la que no se pudo reconectar es casi seguro debido a los valores de AliveInterval (respuesta de kasperd). El uso de la opción ExitOnForwardFailure debería permitir que el tiempo de espera se produzca correctamente antes de volver a conectar, 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 DigitalOcean VPS (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 de repente ha fallado cuatro veces en las últimas 24 horas. Lo mismo sucedió hace un tiempo en otro proveedor de VPS: meses de funcionamiento perfecto, y de repente múltiples fallas rápidas.
Tengo un script en la máquina A que ejecuta automáticamente el comando del 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
.
Entrar en el sshd /var/log/secure
en el servidor muestra estos errores:
bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X
Resolver requiere reiniciar el VPS. Hasta entonces, todos los intentos de reconexión dan el mensaje "error de reenvío de puerto remoto" y no funcionarán. Ahora es el punto donde el túnel solo dura aproximadamente 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 está cerrando los puertos cuando se pierde la conexión. No puedo explicar por qué, o por qué sucedería repentinamente ahora después de meses de operación casi perfecta.
Para aclarar, primero necesito entender por qué sshd se niega a escuchar en los puertos después de que falla el túnel, lo que parece ser causado por sshd que deja los puertos abiertos y nunca los cierra. Ese parece ser el principal problema. Simplemente no estoy seguro de qué harí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).
fuente
Respuestas:
Estoy de acuerdo con MadHatter, que es probable que se trate de reenvíos de puertos desde conexiones ssh difuntas. Incluso si su problema actual resulta ser otra cosa, puede esperar encontrarse con esas conexiones ssh obsoletas tarde o temprano.
Hay tres formas en que pueden ocurrir conexiones inactivas:
Averiguar cuál de los tres anteriores está sucediendo no es muy importante, porque hay un método que abordará los tres. Ese es el uso de mensajes keepalive.
Debe buscar la
ClientAliveInterval
palabra clavesshd_config
y elServerAliveInterval
intervalo parassh_config
o~/.ssh/config
.Ejecutar el
ssh
comando en un bucle puede funcionar bien. También es una buena idea insertar un modo de suspensión en el bucle para que no termine 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 finalizado en el servidor, puede terminar en una situación en la que la nueva conexión ssh está activa, pero no tiene reenvíos de puertos. Para evitar eso, debe usar la
ExitOnForwardFailure
palabra clave en el lado del cliente.fuente
-o ExitOnForwardFailure yes
es exactamente lo que necesitaba. Así que esa es una cosa menos que necesito resolver. Para pensar, iba a escribir un script de Python para analizar esos mensajes de advertencia. Esto es mucho más simple. : DExitOnForwardFailure
al escribir mi respuesta. Lo he agregado a la respuesta ahora.-o ExitOnForwardFailure=yes
(tenga en cuenta el signo igual). Entonces, si alguien se encuentra con esto, no copie y pegue de mi comentario anterior, no funcionará. : PPuede encontrar el proceso que vincula el puerto en ese servidor con
Parece muy probable que sea medio difunto
sshd
, pero ¿por qué hacer suposiciones cuando puede tener datos? También es una buena manera para que un script encuentre un PID para enviar la señal 9 antes de intentar abrir el túnel nuevamente.fuente
Para mí, cuando un
ssh
túnel se desconecta, la conexión tarda un tiempo en restablecerse, por lo que elssh
proceso continúa bloqueándose, dejándome sin túneles activos y no sé por qué. Una solución alternativa es ponerssh
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 nuevos procesos. El-o ServerAliveInterval=60
mejora la fiabilidad de su conexión actual.Se puede repetir el
ssh
comando de frecuencia, por ejemplo, en unacron
, o, en un bucle en el script, por ejemplo, en la siguiente, corremos elssh
comando de cada 3 minutos:fuente
-o ExitOnForwardFailure=yes
era lo que estaba buscando, muchas gracias!En mi experiencia, ssh tiene el hábito un poco molesto de no salir limpiamente si 'algo' todavía se está ejecutando en el sistema remoto. Por ejemplo, comenzó en segundo plano. Puedes reproducir esto de la siguiente manera:
Su ssh cerrará sesión, pero en realidad no cerrará la sesión, hasta que finalice el proceso remoto (lo cual no ocurrirá, porque es un bucle 'while true'). Puede 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, no puede ser reutilizado por su proceso local.
fuente
ssh -o ConnectTimeout=10 -o BatchMode=yes -gnN -R *:X:localhost:X root@$TUNSRV 1>>tunnel.log 2>&1 &
para que SSH no ejecute nada excepto el túnel en sí, específicamente debido a la opción -N. Todo lo que se mantiene abierto se realiza en el servidor remoto B utilizando sshd.