Come mantenere attivo un tunnel SSH con autossh e systemd

Avvia il tunnel come servizio systemd con Restart=always e usa come comando autossh -M 0 -N -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes. Le opzioni keepalive fanno accorgere ssh di una connessione morta, autossh la riavvia e systemd riavvia tutto dopo un crash o all'avvio. Usa una chiave dedicata su un account che può aprire solo quel tunnel.

Aggiornata il . autossh 1.4g, systemd 257 e OpenSSH 10.0 su Debian 13 in container privilegiati usa e getta.

1. Crea una chiave per il tunnel

Sulla macchina che avvia il tunnel, crea un account locale e una chiave senza passphrase, perché il servizio parte senza nessuno presente. Poi salva la chiave host del server, così la prima connessione non si ferma a chiedere:

sudo apt install autossh
sudo useradd -m -s /usr/sbin/nologin tunnel
sudo -u tunnel mkdir -m 700 /home/tunnel/.ssh
sudo -u tunnel ssh-keygen -t ed25519 -N "" -C tunnel -f /home/tunnel/.ssh/id_ed25519
ssh-keyscan -t ed25519 server | sudo -u tunnel tee /home/tunnel/.ssh/known_hosts

Confronta quella chiave host con la vera impronta del server prima di fidarti. Vedi known_hosts spiegato.

2. Limita l'account sul server

Una chiave senza passphrase su una macchina remota dovrebbe aprire solo questo tunnel. Sul server, crea un account chiamato tunnel e metti la chiave pubblica nel suo ~/.ssh/authorized_keys:

restrict,port-forwarding ssh-ed25519 AAAA... tunnel

Poi aggiungi questo in fondo a /etc/ssh/sshd_config:

Match User tunnel
  AllowTcpForwarding remote
  PermitListen localhost:2222
  X11Forwarding no
  ForceCommand /usr/sbin/nologin
sudo sshd -t && sudo systemctl reload ssh

Abbiamo provato il risultato con questa chiave:

TentativoRisultato
-R 2222:localhost:22Funziona
-R 2223:localhost:22remote port forwarding failed for listen port 2223
Eseguire un comando o una shellThis account is currently not available.
-L 9000:localhost:22Connessione chiusa, non passa nulla

L'ultima riga richiede il blocco Match. Con il solo permitlisten="localhost:2222" in authorized_keys, nella nostra prova un inoltro -L funzionava ancora, e permetteva alla chiave di raggiungere i servizi sul loopback del server. Altre informazioni sulle opzioni delle chiavi sono in come limitare una chiave SSH.

3. Crea il servizio

Salva questo come /etc/systemd/system/autossh-tunnel.service:

[Unit]
Description=Reverse SSH tunnel to server
Wants=network-online.target
After=network-online.target

[Service]
User=tunnel
Environment=AUTOSSH_GATETIME=0
ExecStart=/usr/bin/autossh -M 0 -N -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -i /home/tunnel/.ssh/id_ed25519 -R 2222:localhost:22 tunnel@server
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now autossh-tunnel.service
systemctl status autossh-tunnel

Cosa fa ogni parte

  • -M 0 disattiva la porta di monitoraggio di autossh, che quindi riavvia ssh solo quando ssh termina. Il README di autossh suggerisce le opzioni keepalive in sostituzione della porta di monitoraggio.
  • ServerAliveInterval=30 e ServerAliveCountMax=3 fanno uscire ssh dopo circa 90-120 secondi di silenzio dal server. Nella nostra prova, un intervallo di 5 secondi con lo stesso conteggio ha impiegato 20 secondi, e un congelamento di 100 secondi con questi valori non lo ha fatto scattare.
  • ExitOnForwardFailure=yes fa uscire ssh se la porta non si può aprire. Senza, puoi ritrovarti con una connessione viva ma senza tunnel.
  • AUTOSSH_GATETIME=0 fa continuare a provare autossh anche se il primo tentativo fallisce, cosa importante all'avvio.
  • Restart=always fa ripartire il servizio se muore autossh stesso.
  • Non usare qui l'opzione -f di autossh, perché systemd si aspetta che il processo resti in primo piano.

4. Guardalo riprendersi

Cosa abbiamo fattoCosa è successo
Ucciso la sessione sul serverautossh ha avviato subito un nuovo ssh
Congelato il server per 28 secondi, con intervallo di 5 secondiTimeout, server server not responding. dopo 20 secondi, poi una nuova connessione quando il server è tornato
Ucciso autossh con kill -9, e il suo sshsystemd ha riavviato il servizio e NRestarts è andato a 1

Puoi seguirlo tu stesso con journalctl -u autossh-tunnel -f. Sul server, ss -ltn | grep 2222 mostra la porta.

Se la porta resta occupata dopo un guasto di rete

Dopo un vero guasto, il server può tenere ancora la vecchia connessione e la sua porta, quindi la nuova fallisce con remote port forwarding failed finché la vecchia non scade. Nel blocco Match sul server, aggiungi:

  ClientAliveInterval 30
  ClientAliveCountMax 3

Il server allora scollega i client morti dopo circa 90 secondi e i nuovi tentativi riescono.

Per gli altri motivi per cui la porta può essere occupata, vedi tunnel SSH: Address already in use e remote port forwarding failed.

Ti serve davvero autossh

Con systemd e le opzioni keepalive funziona anche ssh semplice. ssh termina e Restart=always lo rilancia. Sostituisci il comando nell'unità con:

ExecStart=/usr/bin/ssh -N -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -i /home/tunnel/.ssh/id_ed25519 -R 2222:localhost:22 tunnel@server

Nella nostra prova si è ripreso da una sessione uccisa con un riavvio di systemd, dopo i 10 secondi di RestartSec. autossh riparte prima, ed è l'opzione se non hai systemd.

Una differenza che abbiamo visto: systemctl restart ha registrato status=1/FAILURE per autossh mentre si fermava. Il servizio è comunque ripartito normalmente.

Domande

Cosa fa autossh -M 0?

Disattiva la porta di monitoraggio. autossh riavvia ssh solo quando ssh esce, e le opzioni ServerAliveInterval e ServerAliveCountMax fanno uscire ssh quando la connessione muore.

Serve autossh se uso systemd?

Non sempre. Anche ssh da solo, con le opzioni keepalive e Restart=always, torna su. autossh riparte prima e funziona anche senza systemd.

Perché il tunnel inverso fallisce dopo un'interruzione di rete?

Il server può tenere ancora la vecchia connessione e la sua porta. Aggiungi sul server ClientAliveInterval 30 e ClientAliveCountMax 3, così chiude i client morti dopo circa 90 secondi.

Fonti

Altro in Tunnel e jump host

Tutte le guide