Come creare un tunnel SSH inverso per un computer dietro NAT

Sulla macchina dietro NAT esegui ssh -N -R 2222:localhost:22 user@server, dove server ha un indirizzo pubblico. Poi, su quel server, esegui ssh -p 2222 user@localhost per raggiungere la macchina nascosta. Di default la porta ascolta solo sul loopback del server, quindi non è esposta a internet a meno che tu non imposti GatewayPorts.

Aggiornata il . Client e server OpenSSH 10.0 su Debian 13, in container usa e getta sulla stessa rete, con un container che faceva la parte della macchina dietro NAT.

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:...
noSolo loopbackSolo loopback, l'indirizzo viene ignorato
clientspecifiedSolo loopbackTutti gli indirizzi, raggiungibile da altre macchine
yesTutti gli indirizziTutti 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 no e usa -J come 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.

Fonti

Altro in Tunnel e jump host

Tutte le guide