Come funziona
Una macchina dietro NAT non può accettare connessioni in ingresso, ma può farne in uscita. Quindi si collega a un server con indirizzo pubblico e gli chiede di mettersi in ascolto su una porta. Le connessioni a quella porta tornano indietro attraverso la connessione SSH già aperta.
Per gli altri due tipi di inoltro, vedi tunnel SSH locali, remoti e dinamici.
Entrare via SSH nella macchina nascosta
La macchina nascosta deve avere in funzione un proprio server SSH. Sulla macchina nascosta:
ssh -N -o ExitOnForwardFailure=yes -R 2222:localhost:22 user@server
-N non esegue alcun comando remoto. -R 2222:localhost:22 significa che la porta 2222 sul server porta alla porta 22 di questa macchina. Aggiungi -f per metterlo in background.
Sul server puoi vedere la porta e usarla:
$ ss -ltn | grep 2222
LISTEN 0 128 127.0.0.1:2222 0.0.0.0:*
LISTEN 0 128 [::1]:2222 [::]:*
$ ssh -p 2222 hiddenuser@localhost
Dal tuo portatile, passa dal server in un solo comando:
ssh -J user@server -p 2222 hiddenuser@localhost
Per non confondere le chiavi host, dato che localhost potrebbe indicare tante macchine, metti questo in ~/.ssh/config:
Host home
HostName localhost
Port 2222
User hiddenuser
ProxyJump user@server
HostKeyAlias home
Mostrare un'app web locale
ssh -N -R 8080:localhost:3000 user@server
Ora curl http://localhost:8080/ sul server raggiunge la porta 3000 della tua macchina. Nella nostra prova, da un'altra macchina, curl http://server:8080/ è stato rifiutato finché non abbiamo cambiato GatewayPorts.
Con la porta 0, il server sceglie una porta libera e ssh la stampa:
$ ssh -N -R 0:localhost:3000 user@server
Allocated port 33341 for remote forward to localhost:3000
GatewayPorts: chi può raggiungere la porta
Questa impostazione sta nel file sshd_config del server e vale no di default. Quello che abbiamo misurato:
| GatewayPorts | -R 8080:... | -R 0.0.0.0:8080:... |
|---|---|---|
no | Solo loopback | Solo loopback, l'indirizzo viene ignorato |
clientspecified | Solo loopback | Tutti gli indirizzi, raggiungibile da altre macchine |
yes | Tutti gli indirizzi | Tutti gli indirizzi |
Con yes, nella nostra prova anche -R localhost:8080:... ascoltava su tutti gli indirizzi. Se ti serve l'accesso dall'esterno, clientspecified lascia la scelta al client, e il firewall deve comunque permettere la porta.
Tenerlo privato
- Lascia
GatewayPorts noe usa-Jcome sopra. Così solo chi può fare login sul server raggiunge la porta. - Ricorda gli altri utenti del server. Il loopback è condiviso da tutti quelli che sono collegati lì. Possono raggiungere la porta, e il servizio dietro di essa ha comunque bisogno di un proprio login.
- Usa una chiave e un account dedicati al tunnel, perché la macchina dietro NAT conserva una chiave che può fare login sul tuo server. La guida su autossh mostra una configurazione limitata già provata.
Quando la porta è occupata
Con ExitOnForwardFailure=yes, ssh si ferma e termina con codice 255:
Error: remote port forwarding failed for listen port 2222
Senza, ricevi solo un Warning e ssh resta connesso senza tunnel, ed è facile non accorgersene. Una causa comune è una vecchia connessione che tiene ancora la porta sul server. Anche AllowTcpForwarding no o una regola PermitListen sul server danno lo stesso tipo di errore.
Tenerlo sempre attivo
Un semplice ssh -R termina quando la connessione cade, e nulla lo riavvia. Per un tunnel permanente, segui autossh e systemd.
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 fa il contrario: apre una porta sul server che riporta alla tua macchina.
Perché le altre macchine non raggiungono la porta del tunnel inverso?
Con il valore predefinito GatewayPorts no, il server ascolta solo sul suo loopback. Imposta GatewayPorts clientspecified o yes in sshd_config e apri la porta nel firewall.
Come tengo attivo un tunnel SSH inverso?
Un semplice ssh -R finisce quando la connessione cade. Fallo girare con autossh e systemd, così riparte da solo.