Pregunta ¿Cómo mantener confiablemente abierto un túnel SSH?


Uso un túnel SSH del trabajo para recorrer varios firewalls idóticos (está bien con mi jefe :)). El problema es que, después de un tiempo, la conexión ssh generalmente se cuelga y el túnel se rompe.

Si al menos pudiera monitorear el túnel automáticamente, podría reiniciar el túnel cuando se cuelgue, pero ni siquiera he encontrado una manera de hacerlo.

¡Puntos de bonificación para el que puede decirme cómo evitar que mi conexión ssh se cuelgue, por supuesto!


200


origen


¿Tu túnel está muerto porque estás inactivo? Tuve este problema al tunelizar puertos desde mi teléfono, así que finalmente terminé generando comandos ficticios en la conexión para hacerlo "vivo" usando el watch comando como: watch -n1 60 echo "wiiiii". Túnel no morirá a menos que la red se rompa o no la uses. - erm3nda
Relacionado: unix.stackexchange.com/q/200239 - sampablokuper


Respuestas:


Parece que necesitas autossh. Esto monitoreará un túnel ssh y lo reiniciará según sea necesario. Lo hemos usado durante un par de años y parece funcionar bien.

autossh -M 20000 -f -N your_public_server -R 1234:localhost:22 -C

Más detalles sobre el parámetro -M aquí


239



+1 para autossh, hace lo que dice en la lata. Creo que parte de su funcionalidad también es enviar paquetes de estilo keep-alive para evitar cualquier tipo de tiempo de espera. - akent
¿Podría poner el túnel de ejemplo usando autossh en la respuesta? - Ehtesh Choudhury
autossh -f -nNT -i ~/keypair.pem -R 2000:localhost:22 username@myoutsidebox.com   Puede observar que configuré esto usando -nNT que no crea un terminal remoto para poder poner autossh en segundo plano, y la opción -i para que SSH use un archivo .pem. Si va a mantener una conexión abierta todo el tiempo, definitivamente recomiendo pasar por la configuración adicional. - juckele
Por lo que vale, parece que normalmente es mejor omitir el -M parámetro: bugs.debian.org/cgi-bin/bugreport.cgi?bug=351162 - rinogo
Si no funciona y está usando claves, verifique esta respuesta: serverfault.com/a/545093/288788 - muttonUp


Todos los cortafuegos con estado se olvidan de una conexión después de no ver un paquete para esa conexión durante un tiempo (para evitar que las tablas de estado se llenen de conexiones donde ambos extremos murieron sin cerrar la conexión). La mayoría de las implementaciones de TCP enviarán un paquete keepalive después de un largo tiempo sin escuchar del otro lado (2 horas es un valor común). Sin embargo, si hay un cortafuegos con estado que se olvida de la conexión antes de poder enviar los paquetes keepalive, una conexión larga pero inactiva morirá.

Si ese es el caso, la solución es evitar que la conexión quede inactiva. OpenSSH tiene una opción llamada ServerAliveInterval que se puede utilizar para evitar que la conexión permanezca inactiva durante demasiado tiempo (como beneficio adicional, detectará cuándo el par murió antes, incluso si la conexión está inactiva).


34



El intervalo especificado está en segundos, por lo que puede proporcionar algunos ajustes finos. Si su cortafuegos con estado tiene un tiempo de inactividad de 5 minutos, entonces 60 o 120 segundos son suficientes para mantener la conexión abierta. Es una de las formas en que mantengo abiertas mis sesiones ssh a través de mi enrutador doméstico. - Darren Hall
Gracias, esto ayudó. Pero tenga en cuenta (de una respuesta de menor rango aquí, superuser.com/a/146641/115515) que si especifica ServerAliveInterval y no ServerAliveCountMax, puede encontrar que ssh se desconecta intencionalmente antes de lo que deseaba. - metamatt
@metamatt, esa respuesta de rango inferior a la que hace referencia es de menor rango por una buena razón: ES INCORRECTA. - Lambart


En su propia máquina mac o linux, configure su ssh para mantener vivo el servidor ssh cada 3 minutos. Abra una terminal y vaya a su .ssh invisible en su hogar:

cd ~/.ssh/ 

luego crea un archivo de configuración de 1 línea con:

echo "ServerAliveInterval 180" >> config

también deberías agregar:

ServerAliveCountMax xxxx (high number)

el valor predeterminado es 3, por lo que ServerAliveInterval 180 dejará de enviarse después de 9 minutos (3 del intervalo de 3 minutos especificado por ServerAliveInterval).


22



Tenga en cuenta que su comando no es recomendable si ya tiene un archivo de configuración. Usando >> para la redirección sería mucho mejor! - Peltier
por que ServerAliveInterval 180 danos 6 minutos? la intuición me hace probar esto: 180/60 == 3. También lo hace ServerAliveInterval trabajar en múltiplos de 30 segundos? - nemesisfixx
@mcnemesis: ServerAliveInterval 180 significa 3 minutos. ServerAliveCountMax por defecto de 3 significa 3 de esos intervalos, entonces 9 minutos. - metamatt
Estoy votando esta respuesta porque gracias por mencionar ServerAliveCountMax, y lo que sucede si especifica ServerAliveInterval sin ServerAliveCountMax. Pero al igual que en los comentarios anteriores, noto que el cálculo de "dejará de enviar después" es incorrecto, y creo que esta respuesta sería mejor si solo proporcionara la información sobre estas opciones, sin decirnos cómo aplicarlas con comandos de cd y echo . - metamatt
Bajar votos porque no tiene sentido establecer ServerAliveCountMax en un "número alto". ServerAliveCountMax especifica cuántas veces intentará enviar el mensaje "keepalive" antes de darse por vencido. El valor predeterminado es 3, por lo que con ServerAliveInterval 180, dejará de enviar SOLO si el servidor NO HA RESPONDIDO después de 9 minutos, en cuyo caso su conexión probablemente esté realmente muerta. - Lambart


He usado el siguiente script Bash para seguir generando nuevos túneles ssh cuando el anterior muere. Usar una secuencia de comandos es útil cuando no quiere o no puede instalar paquetes adicionales o usar el compilador.

while true
do
  ssh <ssh_options> [user@]hostname
  sleep 15
done

Tenga en cuenta que esto requiere un archivo de clave para establecer la conexión automáticamente, pero ese también es el caso de autossh.


20



Debería agregar las razones por las que usaría este script sobre autossh, o simplemente es más fácil de esta manera? - kyrias
Esto no ayudaría si ssh se congela, ¿verdad? - nafg
Ayuda si no puede instalar cosas en el servidor. autossh no viene preinstalado y la burocracia a veces es muy obtusa. - quarkex
Sí, preferible no tener que instalar cosas. Lo he estado haciendo de esta manera durante un año como mi única forma de mantener accesible una máquina remota (incluso configurar el crontab para ejecutarlo al reiniciar). Nunca falla, y más importante, sé por qué nunca fallará. - sudo


Seguro que me parece que están malinterpretando ServerAliveCountMax. Según entiendo los documentos, es la cantidad de mensajes activos del servidor los que pueden quedar sin respuesta sin que se termine la conexión. Por lo tanto, en casos como el que estamos discutiendo aquí, configurarlo a un valor alto solo asegurará que una conexión colgada no se detecte y se termine.

Simplemente configurar ServerAliveInterval debería ser suficiente para resolver el problema con un cortafuegos olvidándose de la conexión, y dejar ServerAliveCountMax bajo permitirá que el extremo de origen note la falla y finalice si la conexión falla de todos modos.

Lo que quiere es, 1) que la conexión permanezca abierta permanentemente en circunstancias normales, 2) que no se detecte la conexión y que el lado de origen salga cuando falla, y 3) que el comando ssh se vuelva a emitir cada vez que se conecta Exits (cómo lo haces depende mucho de la plataforma, el script "while true" sugerido por Jawa es de una manera, en OS XI realmente se configura un elemento de lanzamiento).


9





Siempre usa ServerAliveInterval Opción SSH en caso de que los problemas del túnel sean generados por sesiones expiradas de NAT.

Siempre use un método de reaparición en caso de que la conectividad se interrumpa por completo, tiene al menos tres opciones aquí:

  • programa autossh
  • script bash (while true do ssh ...; sleep 5; done) no elimine el comando de reposo, ssh puede fallar rápidamente y reaparecerá demasiados procesos
  • /etc/inittab, para tener acceso a una caja enviada e instalada en otro país, detrás de NAT, sin reenviar el puerto a la caja, puede configurarlo para crear un túnel ssh de nuevo:

    tun1:2345:respawn:/usr/bin/ssh -i /path/to/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip 'sleep 365d'
    
  • secuencia de comandos upstart en Ubuntu, donde /etc/inittab no está disponible:

    start on net-device-up IFACE=eth0
    stop on runlevel [01S6]
    respawn
    respawn limit 180 900
    exec ssh -i /path/to/rsaKey -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip
    post-stop script
        sleep 5
    end script
    

o siempre use ambos métodos.


9



+1 para la opción en línea en caso de que no lo desee para todas sus conexiones SSH - user1146334
Usted escribe "en caso de que la conectividad baje por completo". Ahora no entiendo, ¿qué problemas se corrigen automáticamente y qué no? Pensé, por supuesto, que se haría cargo de cualquier conexión rota, como desconectar el cable por unas horas, ¿pero quizás no? - Mads Skjern


Systemd es ideal para esto.

Crea un archivo de servicio /etc/systemd/system/sshtunnel.service que contiene:

[Unit]
Description=SSH Tunnel
After=network.target

[Service]
Restart=always
RestartSec=20
User=sshtunnel
ExecStart=/bin/ssh -NT -o ServerAliveInterval=60 -L 5900:localhost:5900 user@otherserver

[Install]
WantedBy=multi-user.target

(Modificar el comando ssh para adaptarse)

  • esto se ejecutará como usuario sshtunnel así que asegúrese de que el usuario exista primero
  • problema systemctl enable sshtunnel para configurarlo para que comience en el momento del arranque
  • problema systemctl start sshtunnel comenzar de inmediato

Actualización enero 2018: algunas distribuciones (por ejemplo, Fedora 27) pueden usar la política de SELinux para evitar el uso de SSH desde systemd init, en cuyo caso será necesario crear una política personalizada para proporcionar las exenciones necesarias.


8



Esto se ve muy similar a mi esencia: gist.github.com/guettli/... Comentarios son bienvenidos! - guettli
Excelente para un systemd sistema. Si uno usa Restart=on-failure luego, matar manualmente al cliente SSH no dará lugar a un reinicio por sistema como cliente SSH con salida exitosa. - David Tonhofer
Si desea iniciar ssh desde un script (bash) dado como argumento para ExecStart por ejemplo, para construir el ssh lista de argumentos, hacer verificaciones básicas, etc. luego llamar desde el script como tal exec /bin/ssh -N .... Aquí está mi comando: exec /bin/ssh -N -oExitOnForwardFailure=Yes -oTCPKeepAlive=no -oServerAliveInterval=5 -oServerAliveCountMax=6 -i "${LOCAL_PRIVATE_KEY}" -L "${TUNNEL_INLET}:${TUNNEL_OUTLET}" "${REMOTE_USER}@${REMOTE_MACHINE}" dónde TUNNEL_INLET="127.0.0.1:3307" y TUNNEL_OUTLET="127.0.0.1:3306" - David Tonhofer


Resolví este problema con esto:

Editar

~/.ssh/config

Y añadir

ServerAliveInterval 15
ServerAliveCountMax 4

De acuerdo a página man para ssh_config:

ServerAliveCountMax
         Sets the number of server alive messages (see below) which may be
         sent without ssh(1) receiving any messages back from the server.
         If this threshold is reached while server alive messages are
         being sent, ssh will disconnect from the server, terminating the
         session.  It is important to note that the use of server alive
         messages is very different from TCPKeepAlive (below).  The server
         alive messages are sent through the encrypted channel and there‐
         fore will not be spoofable.  The TCP keepalive option enabled by
         TCPKeepAlive is spoofable.  The server alive mechanism is valu‐
         able when the client or server depend on knowing when a connec‐
         tion has become inactive.

         The default value is 3.  If, for example, ServerAliveInterval
         (see below) is set to 15 and ServerAliveCountMax is left at the
         default, if the server becomes unresponsive, ssh will disconnect
         after approximately 45 seconds.  This option applies to protocol
         version 2 only.

 ServerAliveInterval
         Sets a timeout interval in seconds after which if no data has
         been received from the server, ssh(1) will send a message through
         the encrypted channel to request a response from the server.  The
         default is 0, indicating that these messages will not be sent to
         the server.  This option applies to protocol version 2 only.

6



Cada 15 segundos parece muy a menudo hacer ping al servidor. - Lambart
@Lambart pero si la conexión es escamosa y se desconectan las conexiones a menudo, al menos detecta una conexión inactiva y ofrece la oportunidad de volver a intentarlo antes. - binki


ExitOnForwardFailure yes es un buen complemento de las otras sugerencias. Si se conecta pero no puede establecer el reenvío del puerto, es tan inútil para usted como si no se hubiera conectado en absoluto.


3



Esta es una muy buena idea. Incluso autossh es inútil si la conexión anterior se percibe como temporizada antes en el lado remoto que en el host local, ya que en este caso el host local intentará conectarse nuevamente, pero no se puede establecer el reenvío porque el puerto aún está abierto. - Raúl Salinas-Monteagudo


He tenido la necesidad de mantener un túnel SSH a largo plazo. Mi solución se ejecutaba desde un servidor Linux, y es solo un pequeño programa en C que reagrupa ssh mediante la autenticación basada en claves.

No estoy seguro acerca del ahorcamiento, pero he tenido la muerte de túneles debido a tiempos muertos.

Me encantaría proporcionar el código para el respawner, pero parece que no puedo encontrarlo ahora.


1





mientras que hay herramientas como autossh que ayudan a reiniciar la sesión de ssh ... lo que encuentro que es realmente útil es ejecutar el comando 'pantalla'. Te permite REANUDAR tus sesiones ssh incluso después de desconectarte. Especialmente útil si su conexión no es tan confiable como debería ser.

... no te olvides de marcar esta es la respuesta 'correcta' si te ayuda k! ;-)


1



... pero la pregunta era cómo mantener abiertos los túneles SSH, no solo una sesión terminal. ¡Sin embargo, la pantalla ES genial! - akent
Ya uso la pantalla, pero no resuelve mi problema: - Gracias por tu respuesta, sin embargo. - Peltier