Salva ogni tunnel in ~/.ssh/config
Riscrivere ogni volta le opzioni -L e -R è il modo più sicuro per confondere le porte. Dai invece un nome a ogni tunnel, con un suo blocco Host:
Host db-tunnel
HostName 203.0.113.10
User deploy
LocalForward 127.0.0.1:5432 127.0.0.1:5432
ExitOnForwardFailure yes
Host dev-share
HostName 203.0.113.10
User deploy
RemoteForward 127.0.0.1:9000 127.0.0.1:3000
Host socks
HostName 203.0.113.10
User deploy
DynamicForward 127.0.0.1:1080
Ogni riga è la forma da file di configurazione di un'opzione da riga di comando: LocalForward è -L, RemoteForward è -R e DynamicForward è -D. Prima vengono indirizzo e porta di ascolto, poi uno spazio, poi la destinazione. Come con le opzioni, la destinazione di un inoltro locale la risolve il server, quindi lì 127.0.0.1 indica il server stesso. Se i tre tipi sono nuovi per te, parti da tunnel SSH locali, remoti e dinamici spiegati.
Usa un nome a parte per i tunnel, non l'Host con cui fai login tutti i giorni. Altrimenti ogni login prova ad aprire le stesse porte, e il secondo stampa Address already in use.
Avvia un tunnel per nome
ssh -f -N db-tunnel
-N non esegue nessun comando remoto, quindi la connessione porta solo gli inoltri. -f manda ssh in background dopo il login, così la richiesta di passphrase o password arriva comunque prima a te. Ora lo strumento per il database può collegarsi a 127.0.0.1:5432.
Con ExitOnForwardFailure yes, una porta già occupata ferma ssh con codice di uscita 255 invece di lasciare una connessione senza tunnel. Ecco cosa succede se avvii due volte lo stesso tunnel:
bind [127.0.0.1]:5432: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 5432
Could not request local forwarding.
Per avviare più tunnel salvati insieme:
for t in db-tunnel socks; do ssh -f -N "$t"; done
Ferma un tunnel
Un tunnel in background è solo un processo ssh. Senza altro, lo trovi e lo termini:
ps ax | grep '[s]sh -f -N db-tunnel'
pkill -f 'ssh -f -N db-tunnel'
pkill -f colpisce ogni processo la cui riga di comando contiene quel testo. Nelle nostre prove ha terminato anche lo script di shell che aveva avviato il tunnel, perché lo script conteneva le stesse parole. Un socket di controllo è più pulito. Aggiungi tre righe al blocco:
Host db-tunnel
HostName 203.0.113.10
User deploy
LocalForward 127.0.0.1:5432 127.0.0.1:5432
ExitOnForwardFailure yes
ControlMaster auto
ControlPath ~/.ssh/cm-%C
ControlPersist yes
Ora il tunnel risponde ai comandi per nome:
ssh -f -N db-tunnel
ssh -O check db-tunnel
ssh -O exit db-tunnel
Master running (pid=27)
Exit request sent.
Il socket permette anche ad altri comandi ssh e scp verso db-tunnel di riusare la stessa connessione. I dettagli sono in multiplexing SSH con ControlMaster.
Aggiungi o togli un inoltro senza riconnetterti
Con un socket di controllo puoi modificare un tunnel attivo. La connessione e gli altri inoltri restano su:
ssh -O forward -L 127.0.0.1:8081:127.0.0.1:8000 db-tunnel
ssh -O cancel -L 127.0.0.1:8081:127.0.0.1:8000 db-tunnel
cancel vuole esattamente la stessa specifica usata per aggiungere l'inoltro. Funziona anche con -R e -D. Con -R 0:... il server sceglie una porta libera e ssh -O forward la stampa.
Tieni attivo un tunnel salvato
Un tunnel avviato con -f vive quanto la sua connessione SSH. Lo stop del computer, un cambio di Wi-Fi o il riavvio del server lo chiudono. Aggiungi queste righe al blocco perché ssh si accorga di una connessione morta in circa 45 secondi e termini, invece di restare appeso:
ServerAliveInterval 15
ServerAliveCountMax 3
Poi qualcosa deve riavviarlo: un ciclo, un gestore di servizi o autossh per un tunnel SSH persistente.
Errori che rompono i tunnel salvati
- Due punti al posto dello spazio.
LocalForward 5432:127.0.0.1:5432è il formato della riga di comando, non quello del file di configurazione. ssh rispondeMissing target argument, e nella nostra prova quella sola riga sbagliata ha impedito la connessione a tutti gli host del file. - Ascolto su tutte le interfacce.
LocalForward 0.0.0.0:5432 ...oGatewayPorts yeslasciano usare il tunnel ad altre macchine della tua rete. Tieni127.0.0.1se non è proprio quello che vuoi. - Due tunnel sulla stessa porta locale. Parte solo il primo. Dai a ogni tunnel salvato la sua porta.
- Inoltro rifiutato dal server. Se la porta si apre ma le connessioni falliscono con
administratively prohibited, il server haAllowTcpForwardingdisattivato per te.
Domande
Come vedo quali tunnel SSH sono attivi?
Esegui ps ax | grep '[s]sh -f -N' per elencare i processi ssh in background con le loro opzioni. Per un tunnel con socket di controllo risponde direttamente ssh -O check nome. In una sessione interattiva premi Invio e scrivi ~# per vedere le connessioni inoltrate.
Posso avviare più tunnel con un solo comando?
Sì. Metti più righe LocalForward o DynamicForward in un solo blocco Host e si aprono tutte con un solo ssh -f -N nome. Se una porta è occupata e ExitOnForwardFailure è attivo, non ne resta aperta nessuna.
Perché il tunnel salvato si ferma dopo lo stop o un cambio di rete?
Il tunnel vive dentro una connessione SSH, e quella connessione muore quando cade la rete. Aggiungi ServerAliveInterval perché ssh se ne accorga, e riavvialo con un ciclo o con autossh.
Fonti
- ssh(1), -f, -N e -O, manuale OpenBSD
- ssh_config(5), LocalForward, RemoteForward, DynamicForward, ControlMaster
- sshd_config(5), AllowTcpForwarding e GatewayPorts