Quale ti serve?
| Opzione | La porta si apre su | Usalo per |
|---|---|---|
-L locale | La tua macchina | Raggiungere un servizio che solo il server può raggiungere, come un database. |
-R remoto | Il server | Far raggiungere al server qualcosa sulla tua macchina, come un sito di sviluppo. |
-D dinamico | La tua macchina | Navigare o collegarti a molti host come se fossi sul server. |
Un modo facile per ricordarli: -L ascolta sulla tua macchina locale, -R ascolta sul server remoto, e -D è dinamico perché la destinazione la sceglie l'app ogni volta.
Inoltro locale: -L
ssh -N -L 8080:localhost:80 user@server
your app -> your machine, port 8080 -> SSH -> server -> localhost:80 as seen by the server
Il formato è porta_locale:destinazione:porta_destinazione. Ora http://127.0.0.1:8080 sulla tua macchina mostra il server web che ascolta solo sull'indirizzo di loopback del server.
Il punto chiave è che la destinazione la risolve il server. localhost indica il server stesso, non la tua macchina. La destinazione può anche essere un altro host raggiungibile dal server, e quell'ultimo tratto non è cifrato da SSH:
ssh -N -L 8080:intranet.example.com:80 user@server
Inoltro remoto: -R
ssh -N -R 9000:localhost:3000 user@server
a program on the server -> server, port 9000 -> SSH -> your machine -> localhost:3000 as seen by your machine
Ora un programma sul server può aprire http://127.0.0.1:9000 e raggiungere l'app che gira sulla tua macchina. Funziona anche quando la tua macchina è dietro NAT, perché è il tuo lato ad aver avviato la connessione.
Inoltro dinamico: -D
ssh -N -D 1080 user@server
your app -> SOCKS proxy on your machine, port 1080 -> SSH -> server -> any host:port the app asks for
Punta un'applicazione che supporta SOCKS a 127.0.0.1:1080. Per provarlo con curl:
curl --socks5-hostname 127.0.0.1:1080 http://intranet.example.com/
--socks5-hostname fa fare la ricerca DNS al server, quindi i nomi interni funzionano e la ricerca non esce dalla tua rete. Il semplice --socks5 risolve il nome sulla tua macchina.
Impostazioni del browser e fughe DNS sono spiegate in come usare SSH come proxy SOCKS.
Più porte, o attraverso un jump host
Ripeti l'opzione per aprire più inoltri sulla stessa connessione:
ssh -N -L 127.0.0.1:8080:localhost:80 -L 127.0.0.1:5433:localhost:5432 user@server
Quando il server sta dietro un bastion, aggiungi -J. L'inoltro parte dall'ultimo server della catena, quindi è quel server a risolvere la destinazione:
ssh -N -J user@bastion -L 127.0.0.1:5433:localhost:5432 user@db-server
Le catene di server sono spiegate in come usare ProxyJump e un jump host.
Eseguire un tunnel senza shell
-Nnon esegue nessun comando remoto. La sessione trasporta solo il tunnel.-fpassa in background dopo il login, così puoi ancora digitare prima una passphrase.-o ExitOnForwardFailure=yestermina con un errore se l'inoltro non può essere creato.
ssh -f -N -o ExitOnForwardFailure=yes -L 127.0.0.1:8080:localhost:80 user@server
Senza ExitOnForwardFailure, ssh stampa un avviso e resta connesso senza un tunnel funzionante, cosa che in uno script confonde. Con l'opzione, una porta locale già in uso termina con codice di uscita 255 e Could not request local forwarding, mentre una porta remota già usata termina con remote port forwarding failed for listen port.
Un'insidia, vista nei nostri test: con un semplice -L 8080:..., ssh ascolta sia su 127.0.0.1 sia su ::1. Se solo uno dei due è occupato, per esempio da un altro programma su IPv4, ssh stampa bind [127.0.0.1]:8080: Address already in use e continua a girare anche con ExitOnForwardFailure=yes. La tua app potrebbe allora raggiungere quell'altro programma. Scrivere l'indirizzo, come in -L 127.0.0.1:8080:..., rende questo un vero errore, quindi usa quella forma negli script.
Per fermare un tunnel in background, trova il suo processo e terminalo:
pgrep -f 'L 127.0.0.1:8080'
kill PID
Per i tunnel che avvii spesso, un socket di controllo ti permette di fermarli per nome con ssh -O exit. Vedi come salvare, avviare e fermare i tunnel SSH.
Per tenere un tunnel nella tua configurazione, usa LocalForward, RemoteForward e DynamicForward:
Host dbtunnel
HostName 203.0.113.10
User user
LocalForward 127.0.0.1:8080 localhost:80
ExitOnForwardFailure yes
Legare solo a localhost
Una porta inoltrata è aperta a chiunque possa raggiungerla, e il servizio dietro di essa può fidarsi delle connessioni provenienti dal server. Per impostazione predefinita ssh si lega solo al loopback, quindi lascialo così a meno che tu non abbia un motivo.
Questi comandi aprono la porta locale a tutta la tua rete. Abbiamo verificato che entrambi ascoltano su tutte le interfacce:
ssh -N -L 0.0.0.0:8080:localhost:80 user@server
ssh -N -g -L 8080:localhost:80 user@server
Per -R decide il server, con GatewayPorts nella sua configurazione di sshd:
| GatewayPorts | -R 9000:... | -R 0.0.0.0:9000:... |
|---|---|---|
no (predefinito) | Solo loopback | Solo loopback, senza errore |
clientspecified | Solo loopback | Tutte le interfacce |
yes | Tutte le interfacce | Tutte le interfacce, e anche 127.0.0.1:9000 si apre su tutte le interfacce |
Quindi, se la tua porta -R non è raggiungibile dall'esterno, di solito la causa è GatewayPorts. Esporre a internet un servizio del tuo portatile in questo modo raramente è ciò che vuoi. Se ti serve, preferisci clientspecified e aggiungi una regola del firewall.
Quando il server rifiuta
Lo controlla AllowTcpForwarding nella configurazione di sshd del server. I valori sono yes (predefinito), no, local (consente -L e -D) e remote (consente -R).
- Un
-Lo-Dbloccato si connette senza problemi. L'errore arriva solo quando qualcosa usa la porta:channel 2: open failed: administratively prohibited: open failed. - Un
-Rbloccato diceremote port forwarding failed for listen port.
La pagina di manuale osserva che disattivare l'inoltro serve a poco se gli utenti hanno anche una shell, perché possono eseguire un proprio forwarder. Per limitare davvero qualcuno, togli anche la shell, come in un utente solo tunnel per un database.
Altri due errori capitano spesso. Quando la porta locale o remota è occupata, vedi Address already in use e remote port forwarding failed. Quando le connessioni attraverso il tunnel vengono rifiutate, vedi administratively prohibited: open failed.
Domande
Che differenza c'è tra ssh -L e ssh -R?
-L apre una porta sulla tua macchina che porta a qualcosa raggiungibile dal server. -R apre una porta sul server che riporta a qualcosa sulla tua macchina.
Come inoltro più porte con un solo comando ssh?
Ripeti l'opzione: ssh -N -L 127.0.0.1:8080:localhost:80 -L 127.0.0.1:5433:localhost:5432 user@server. Una sola connessione le porta tutte. In ~/.ssh/config aggiungi una riga LocalForward per ogni porta.
Come tengo attivo un tunnel SSH?
Avvialo con -N e -o ExitOnForwardFailure=yes, e fallo ripartire dopo una caduta con autossh o un servizio systemd. Vedi autossh e systemd.
Perché il tunnel si connette ma non funziona niente?
Il server può vietare l'inoltro con AllowTcpForwarding. Un -L o -D bloccato si connette lo stesso e fallisce solo quando si usa la porta, con administratively prohibited: open failed.
Il port forwarding SSH è sicuro?
Il traffico è cifrato tra la tua macchina e il server SSH. Il tratto dal server alla destinazione no, e una porta che ascolta su 0.0.0.0 la può usare chiunque sulla tua rete, quindi lascia come indirizzo di ascolto 127.0.0.1.