Gestire i tunnel SSH: salvare, avviare e fermare i port forwarding

Salva ogni tunnel come blocco Host in ~/.ssh/config con LocalForward, RemoteForward o DynamicForward, poi avvialo per nome con ssh -f -N nome. Aggiungi al blocco ControlMaster, ControlPath e ControlPersist e potrai fermarlo con ssh -O exit nome, senza cercare il processo. ssh -O forward e ssh -O cancel aggiungono o tolgono un inoltro mentre il tunnel resta attivo.

Aggiornata il . Eseguito con OpenSSH 10.0 su Debian 13 in container usa e getta: un client, un jump host e un server di destinazione con un piccolo server HTTP.

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 risponde Missing 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 ... o GatewayPorts yes lasciano usare il tunnel ad altre macchine della tua rete. Tieni 127.0.0.1 se 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 ha AllowTcpForwarding disattivato 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

Altro in Tunnel e jump host

Tutte le guide