Come mantenere affidabile un tunnel SSH aperto?


235

Uso un tunnel SSH dal lavoro per aggirare vari firewall idotici (va bene con il mio capo :)). Il problema è che dopo un po 'la connessione ssh si blocca e il tunnel si interrompe.

Se potessi almeno monitorare automaticamente il tunnel, potrei riavviare il tunnel quando si blocca, ma non ho nemmeno immaginato un modo per farlo.

Punti bonus per chi può dirmi come impedire che la mia connessione SSH si blocchi, ovviamente!


È il tuo tunnel morto a causa dell'inattività? Ho avuto questo problema quando il tunneling porte dal mio telefono così ho finalmente si è conclusa la deposizione delle uova comandi fittizi sulla connessione per renderlo "vivo" utilizzando il watchcomando come: watch -n1 60 echo "wiiiii". Il tunnel non morirà a meno che la rete non sia interrotta o non la usi.
erm3nda,

Risposte:


281

Sembra che tu abbia bisogno di autossh . Questo monitorerà un tunnel ssh e lo riavvierà secondo necessità. Lo usiamo da un paio d'anni e sembra funzionare bene.

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

Maggiori dettagli sul parametro -M qui


2
+1 per autossh, fa quello che dice sulla scatola. Credo che parte della sua funzionalità sia anche l'invio di pacchetti di stile keep-alive per prevenire qualsiasi tipo di timeout.
Akent

30
Potresti inserire il tunnel di esempio usando autosshnella risposta?
Ehtesh Choudhury,

5
autossh -f -nNT -i ~/keypair.pem -R 2000:localhost:22 username@myoutsidebox.com Potresti notare che ho impostato questo usando -nNT che non crea un terminale remoto in modo da poter mettere l'autossh in background e l'opzione -i per SSH per usare un file .pem. Se hai intenzione di mantenere una connessione sempre aperta, ti consiglio vivamente di eseguire l'installazione aggiuntiva.
juckele,

2
Per quello che vale, sembra che in genere sia meglio omettere il -Mparametro: bugs.debian.org/cgi-bin/bugreport.cgi?bug=351162
rinogo

2
L'ho fatto per riprovare al cambio di rete, funziona bene per me: autossh -M 0 -o "ServerAliveInterval 10" -o "ServerAliveCountMax 2" -L 9999: localhost: 19999 server@example.com
Luke Stanley

39

Tutti i firewall con stato dimenticano una connessione dopo non aver visto un pacchetto per quella connessione per un certo periodo di tempo (per evitare che le tabelle di stato si riempiano di connessioni in cui entrambe le estremità sono morte senza chiudere la connessione). La maggior parte delle implementazioni TCP invierà un pacchetto keepalive dopo molto tempo senza sentire dall'altra parte (2 ore sono un valore comune). Se, tuttavia, esiste un firewall con stato che dimentica la connessione prima che i pacchetti keepalive possano essere inviati, una connessione di lunga durata ma inattiva morirà.

In tal caso, la soluzione è impedire che la connessione diventi inattiva. OpenSSH ha un'opzione chiamata ServerAliveInterval che può essere utilizzata per evitare che la connessione rimanga inattiva per troppo tempo (come bonus, rileverà quando il peer è morto prima anche se la connessione è inattiva).


L'intervallo specificato è in secondi, quindi è possibile fornire una regolazione fine. Se il firewall con stato ha un timeout di inattività di 5 minuti, 60 o 120 secondi sono sufficienti per mantenere aperta la connessione. È uno dei modi in cui mantengo aperte le mie sessioni ssh attraverso il mio router di casa.
Darren Hall,

Grazie, questo mi ha aiutato. Ma nota (da una risposta di livello inferiore qui, superuser.com/a/146641/115515 ) che se specifichi ServerAliveInterval e non ServerAliveCountMax, potresti trovare ssh che si disconnette intenzionalmente prima di quanto desideri.
Metamatt,

4
@metamatt, quella risposta di livello inferiore a cui fai riferimento è di livello inferiore per una buona ragione: È SBAGLIATO.
Lambart,

24

Sul tuo Mac o Linux, configura il tuo SSH per mantenere in vita il server SSH ogni 3 minuti. Apri un terminale e porta il tuo invisibile .ssh a casa tua:

cd ~/.ssh/ 

quindi crea un file di configurazione a 1 riga con:

echo "ServerAliveInterval 180" >> config

dovresti anche aggiungere:

ServerAliveCountMax xxxx (high number)

il valore predefinito è 3, quindi ServerAliveInterval 180 interromperà l'invio dopo 9 minuti (3 dell'intervallo di 3 minuti specificato da ServerAliveInterval).


2
Si noti che il comando non è consigliato se si dispone già di un file di configurazione. Usare >> per il reindirizzamento sarebbe molto meglio!
Peltier,

perché ServerAliveInterval 180ci danno 6 minuti? l'intuizione mi fa provare questo: 180/60 == 3. Quindi, ServerAliveIntervalfunziona in multipli di 30 secondi?
nemesisfixx,

@mcnemesis: ServerAliveInterval 180 significa 3 minuti. ServerAliveCountMax di default 3 indica 3 di questi intervalli, quindi 9 minuti.
Metamatt,

2
Sto votando questa risposta perché grazie per aver menzionato ServerAliveCountMax e cosa succede se si specifica ServerAliveInterval senza ServerAliveCountMax. Ma come i commenti precedenti, noto che il calcolo su "smetterà di inviare dopo" è sbagliato e penso che questa risposta servirebbe meglio se fornisse solo le informazioni su queste opzioni, non dicendoci come applicarle con i comandi cd ed echo .
Metamatt,

20
Downvoting perché non ha senso impostare ServerAliveCountMax su un "numero elevato". ServerAliveCountMax specifica quante volte proverà a inviare il messaggio "keepalive" prima di arrendersi. Il valore predefinito è 3, quindi con ServerAliveInterval 180, smetterà di inviare SOLO se il server NON RISPONDE dopo 9 minuti, nel qual caso la tua connessione è probabilmente completamente interrotta.
Lambart,

22

Ho usato il seguente script Bash per continuare a generare nuovi tunnel ssh quando il precedente muore. L'uso di uno script è utile quando non si desidera o non è possibile installare pacchetti aggiuntivi o utilizzare il compilatore.

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

Si noti che ciò richiede un file di chiavi per stabilire automaticamente la connessione, ma è anche il caso dell'autossh.


2
Dovresti aggiungere qualche motivo per cui dovresti usare questo script su autossh, o è solo che è più facile in questo modo?
kyrias,

4
Questo non aiuterebbe se ssh stesso si blocca, vero?
nafg

1
Aiuta se non riesci a installare cose sul server. autossh non viene preinstallato e la bureucracy a volte è molto ottusa.
Quarkex,

Sì, preferibile non dover installare cose. Lo sto facendo in questo modo da un anno come unico modo per mantenere accessibile una macchina remota (anche impostare crontab per eseguirlo al riavvio). Non è mai fallito e, soprattutto, so perché non fallirà mai.
sudo,

16

Systemd è ideale per questo.

Creare un file di servizio /etc/systemd/system/sshtunnel.servicecontenente:

[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

(Modifica il comando ssh per adattarlo)

  • questo verrà eseguito come utente, sshtunnelquindi assicurati che l'utente esista per primo
  • problema systemctl enable sshtunnelper impostarlo per l'avvio all'avvio
  • problema systemctl start sshtunnelper iniziare immediatamente

Aggiornamento gennaio 2018 : alcune distro (ad esempio Fedora 27) possono utilizzare la politica SELinux per impedire l'uso di SSH da systemd init, nel qual caso sarà necessario creare una politica personalizzata per fornire le esenzioni necessarie.


2
Sembra molto simile alla mia idea : gist.github.com/guettli/… Il feedback è il benvenuto!
Guettli,

Eccellente per un systemdsistema. Se si utilizza Restart=on-failurequindi l'uccisione manuale del client SSH non comporterà un riavvio per sistema come client SSH con uscita con esito positivo.
David Tonhofer,

Se si desidera avviare ssh da uno script (bash) fornito come argomento, ad ExecStartesempio per creare l' sshelenco di argomenti, eseguire controlli di base, ecc., Quindi chiamarlo dallo script in questo modo exec /bin/ssh -N .... Ecco il mio 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}"dove TUNNEL_INLET="127.0.0.1:3307"eTUNNEL_OUTLET="127.0.0.1:3306"
David Tonhofer,

10

Mi sembra sicuramente che tu stia interpretando male ServerAliveCountMax. A quanto ho capito, è il numero di messaggi attivi del server che possono rimanere senza risposta senza che la connessione venga interrotta. Quindi, in casi come quello di cui stiamo discutendo qui, impostarlo su un valore elevato garantirà semplicemente che una connessione sospesa non venga rilevata e terminata!

La semplice impostazione di ServerAliveInterval dovrebbe essere sufficiente per risolvere il problema con un firewall che dimentica la connessione e lasciare ServerAliveCountMax basso consentirà all'estremità di origine di notare l'errore e terminare se la connessione non riesce comunque.

Ciò che si desidera è 1) che la connessione rimanga aperta in modo permanente in circostanze normali, 2) che la connessione non venga rilevata e che il lato di origine venga chiuso in caso di errore e 3) che il comando ssh venga emesso nuovamente ogni volta che esce (il modo in cui lo fai dipende molto dalla piattaforma, lo script "while true" suggerito da Jawa è un modo, su OS XI in realtà imposta un oggetto launchd).


9

Utilizzare sempre l' ServerAliveIntervalopzione SSH nel caso in cui i problemi del tunnel siano generati da sessioni NAT scadute.

Usa sempre un metodo di rigenerazione nel caso in cui la connettività scenda completamente, hai almeno tre opzioni qui:

  • programma autossh
  • bash script ( while true do ssh ...; sleep 5; done) non rimuove il comando sleep, sshpotrebbe fallire rapidamente e rigenererai troppi processi
  • /etc/inittab, per avere accesso a un box spedito e installato in un altro paese, dietro NAT, senza port forwarding al box, puoi configurarlo per creare un tunnel ssh di nuovo a te:

    tun1:2345:respawn:/usr/bin/ssh -i /path/to/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip 'sleep 365d'
    
  • script upstart su Ubuntu, dove /etc/inittabnon è disponibile:

    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 usa sempre entrambi i metodi.


1
+1 per l'opzione in linea nel caso in cui non lo desideri per tutte le tue connessioni SSH
user1146334

Scrivi "nel caso in cui la connettività diminuisca completamente". Ora non capisco, quali problemi si risolve da solo e cosa no? Ho pensato, ovviamente, che si sarebbe preso cura di qualsiasi connessione interrotta, come scollegare il cavo per alcune ore, ma forse no?
Mads Skjern,

6

Ho risolto questo problema con questo:

modificare

~/.ssh/config

E aggiungi

ServerAliveInterval 15
ServerAliveCountMax 4

Secondo la pagina man di 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.

Ogni 15 secondi sembra abbastanza spesso eseguire il ping del server.
Lambart,

@Lambart, ma se la connessione è davvero instabile e spesso interrompe le connessioni, almeno rileva una connessione interrotta e offre l'opportunità di riprovare prima.
binki,

4

ExitOnForwardFailure yesè una buona aggiunta agli altri suggerimenti. Se si connette ma non è in grado di stabilire il port forwarding, è altrettanto inutile per te come se non fosse stato collegato affatto.


Questa è un'ottima idea Anche l'autossh è inutile se la connessione precedente viene percepita come scaduta prima nel lato remoto rispetto all'host locale, poiché in questo caso l'host locale proverà a connettersi di nuovo, ma non è possibile stabilire l'inoltro perché la porta è ancora aperta.
Raúl Salinas-Monteagudo,

1

Ho avuto la necessità di mantenere un tunnel SSH a lungo termine. La mia soluzione era in esecuzione da un server Linux, ed è solo un piccolo programma C che rigenera ssh usando l'autenticazione basata su chiave.

Non sono sicuro dell'impiccagione, ma ho fatto morire i tunnel a causa dei timeout.

Mi piacerebbe fornire il codice per il respawner, ma al momento non riesco a trovarlo.


1

mentre ci sono strumenti come autossh che aiuta a riavviare la sessione ssh ... quello che trovo davvero utile è eseguire il comando 'screen'. Ti permette di RIPRENDERE le tue sessioni ssh anche dopo la disconnessione. Particolarmente utile se la connessione non è affidabile come dovrebbe essere.

... non dimenticare di contrassegnare questa è la risposta "corretta" se ti aiuta k! ;-)


7
... ma la domanda era su come mantenere aperti i tunnel SSH, non solo una sessione terminale. Lo schermo è fantastico però!
Akent

Uso già lo schermo, ma non risolve il mio problema: - / Grazie per la risposta, però.
Peltier,

1

Un po 'di un trucco, ma mi piace usare lo schermo per mantenerlo. Al momento ho un forward remoto che funziona da settimane.

Esempio, iniziando localmente:

screen
ssh -R ......

Quando viene applicato l'inoltro remoto e si dispone di una shell sul computer remoto:

screen
Ctrl + a + d

Ora hai un forward forward senza interruzioni. Il trucco è eseguire lo schermo su entrambe le estremità


1

Recentemente ho avuto questo problema da solo, perché queste soluzioni richiedono di reinserire la password ogni volta che si utilizza un accesso con password Ho usato sshpass in un ciclo insieme a un prompt di testo per evitare di avere la password nel file batch.

Ho pensato di condividere la mia soluzione su questo thead nel caso in cui qualcun altro avesse lo stesso problema:

#!/bin/bash
read -s -p "Password: " pass
while true
do
    sshpass -p "$pass" ssh user@address -p port
    sleep 1
done

0

Ho avuto problemi simili con il mio precedente ISP. Per me è stato lo stesso con qualsiasi connessione tcp, visitare siti Web o inviare posta.

La soluzione era configurare una connessione VPN su UDP (stavo usando OpenVPN). Questa connessione era più tollerante a qualunque cosa causasse le disconnessioni. Quindi è possibile eseguire qualsiasi servizio tramite questa connessione.

Possono esserci ancora problemi con la connessione, ma dal momento che il tunnel sarà più tollerante, ogni sessione ssh avvertirà un breve blocco anziché essere disconnessa.

Per fare ciò avrai bisogno di un servizio VPN online che puoi configurare sul tuo server.


0

Poiché autosshnon soddisfa le nostre esigenze (esiste per errore se non può connettersi al server al primo tentativo), abbiamo scritto un'applicazione bash pura: https://github.com/aktos-io/link- con server

Crea un tunnel inverso per la porta sshd (22) del NODE sul server per impostazione predefinita. Se è necessario eseguire altre azioni (come inoltro di porte aggiuntive, invio di posta sulla connessione, ecc ...) è possibile posizionare script on-connecte on-disconnectcartelle.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.