Marvin Pascale

[B.Log]

20 Maggio 2026

SSH Tunneling

Linux /sys

Per molti utenti, SSH è semplicemente quel comando che permette di collegarsi ad un server remoto:

ssh user@server

In realtà SSH è uno degli strumenti più potenti che abbiamo a disposizione su GNU/Linux. Non serve solo ad aprire una shell remota: può diventare un tunnel cifrato per database, pannelli web, API interne e servizi che non dovrebbero mai essere esposti direttamente su Internet.

Negli ultimi anni ho visto troppe installazioni con PostgreSQL aperto sul mondo, dashboard Kubernetes pubbliche o pannelli di management raggiungibili senza alcun controllo. Nella maggior parte dei casi, bastava usare un tunnel SSH.

Vediamo quindi come sfruttarlo nel modo corretto, con un occhio molto attento alla sicurezza.

Cos’è SSH Tunneling

SSH Tunneling (o port forwarding) permette di trasportare traffico TCP attraverso una connessione SSH cifrata.

In pratica:

  • il servizio rimane privato
  • non serve aprire nuove porte sul firewall
  • il traffico viaggia cifrato
  • si riduce enormemente la superficie di attacco

È una soluzione perfetta ad esempio per:

  • database PostgreSQL/MySQL
  • dashboard interne
  • pannelli Proxmox
  • Grafana
  • servizi self-hosted
  • ambienti di sviluppo

Local Port Forwarding (-L)

Questo è il caso più comune.

Immaginiamo un database PostgreSQL raggiungibile solo dal server remoto:

ssh -N -L 5432:localhost:5432 user@server-remoto

Vediamo cosa significa:

-L 5432:localhost:5432

dice a SSH:

“Ascolta sulla porta 5432 locale e inoltra tutto verso localhost:5432 del server remoto”

A questo punto il database remoto sarà raggiungibile localmente:

psql -h localhost -U postgres

senza esporre PostgreSQL su internet.

Ed è esattamente così che dovrebbe essere configurato un database pubblico: accessibile solo via tunnel o rete privata.

Sicurezza: bind solo su localhost

Una configurazione corretta lato database dovrebbe essere:

listen_addresses = 'localhost'

oppure:

127.0.0.1

Non:

0.0.0.0

a meno che non ci sia una reale necessità.

Lo stesso vale per:

  • Redis
  • Prometheus
  • Grafana
  • pgAdmin
  • pannelli web vari

Se un servizio non deve essere pubblico, non deve ascoltare pubblicamente.

Eseguire il tunnel in background

Un tunnel spesso serve per ore.

Possiamo mandarlo in background:

ssh -f -N -L 5432:localhost:5432 user@server-remoto

dove:

  • -N evita l’apertura della shell remota
  • -f manda il processo in background

Per verificare che il tunnel sia attivo:

lsof -i :5432

oppure:

ss -lntp

Remote Port Forwarding (-R)

Il forwarding remoto fa l’opposto.

Espone un servizio locale attraverso un server remoto.

Esempio:

ssh -N -R 9000:localhost:3000 user@server-remoto

In questo caso:

  • il server remoto espone la porta 9000
  • il traffico viene inoltrato verso il nostro PC locale sulla porta 3000

Molto utile per:

  • demo rapide
  • sviluppo remoto
  • webhook temporanei

Attenzione ai rischi del forwarding remoto

Qui bisogna fare molta attenzione.

Per default OpenSSH limita l’accesso al tunnel al solo localhost remoto. Ed è una scelta molto sensata.

Se abilitate:

GatewayPorts yes

nel file:

/etc/ssh/sshd_config

state potenzialmente esponendo il vostro servizio locale al mondo intero.

Prima di farlo chiedetevi:

  • serve davvero?
  • chi può raggiungere quella porta?
  • il servizio ha autenticazione?
  • c’è un firewall?

In molti casi è meglio usare:

GatewayPorts clientspecified

oppure limitare tutto tramite firewall.

Dynamic Port Forwarding (-D)

Questa modalità trasforma SSH in un proxy SOCKS5.

ssh -N -D 1080 user@server-remoto

A quel punto possiamo configurare il browser usando:

SOCKS5 localhost:1080

Il traffico verrà instradato attraverso il server remoto.

Può essere utile:

  • su Wi-Fi pubblici
  • per accedere a reti aziendali
  • per test geografici
  • per cifrare traffico non sicuro

Bastion Host e Jump Server

Nelle infrastrutture moderne è sempre più comune usare un bastion host.

L’idea è semplice:

  • un solo server esposto
  • tutti gli altri restano privati

Connessione classica:

ssh -J user@bastion user@internal-server

Oppure con tunnel database:

ssh -L 5432:localhost:5432 -J user@bastion user@db-server

È una soluzione estremamente più sicura rispetto ad aprire SSH ovunque.

~/.ssh/config: la svolta

Quando iniziano ad esserci molti tunnel, conviene usare:

~/.ssh/config

Esempio:

Host db-prod
    HostName bastion.example.com
    User deploy
    IdentityFile ~/.ssh/id_ed25519

    LocalForward 5432 db.internal:5432

    ServerAliveInterval 60
    ServerAliveCountMax 3

    ExitOnForwardFailure yes

A quel punto basta:

ssh -fN db-prod

Molto più leggibile e gestibile.

AutoSSH: tunnel persistenti

Le connessioni cadono.

Specialmente:

  • Wi-Fi instabili
  • VPS economiche
  • reti mobili
  • NAT aggressivi

Qui entra in gioco autossh.

Installazione:

apt install autossh

Esempio:

autossh -M 0 -f -N \
-L 5432:db.internal:5432 \
deploy@bastion

Con:

ServerAliveInterval 60
ServerAliveCountMax 3

il tunnel verrà ricreato automaticamente.

systemd: tunnel permanenti

Se il tunnel deve restare sempre attivo, meglio usare systemd.

Esempio:

[Unit]
Description=Tunnel PostgreSQL

After=network.target

[Service]
User=deploy

ExecStart=/usr/bin/autossh -M 0 -N \
-o "ServerAliveInterval=60" \
-o "ServerAliveCountMax=3" \
-L 5432:db.internal:5432 \
[email protected]

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Abilitazione:

systemctl enable --now tunnel-postgres

Best practice fondamentali

Ci sono alcune regole che considero obbligatorie.

1. Disabilitare login password

Usare solo chiavi SSH:

PasswordAuthentication no

2. Disabilitare root login

PermitRootLogin no

3. Usare chiavi moderne

Preferire:

ed25519

Creazione:

ssh-keygen -t ed25519

4. Limitare gli utenti autorizzati

AllowUsers deploy backup

5. Non usare tunnel inutili

Chiudere sempre ciò che non serve.

Un tunnel dimenticato è una superficie di attacco dimenticata.

6. Monitorare i log SSH

Sempre.

journalctl -u ssh

oppure:

/var/log/auth.log

7. Proteggere il bastion host

È il punto più critico dell’infrastruttura.

Consiglio almeno:

  • Fail2ban
  • MFA
  • firewall restrittivo
  • accesso IP-based
  • aggiornamenti costanti

Una nota importante: SSH Forwarding supporta solo TCP

Questa è una limitazione spesso dimenticata: SSH forwarding funziona solo con TCP.

I servizi UDP non possono essere inoltrati direttamente tramite SSH.

Per quelli serve:

  • VPN
  • WireGuard
  • Tailscale
  • soluzioni dedicate

Conclusioni

SSH Tunneling è una di quelle funzionalità che esistono da decenni ma che ancora oggi vengono sottovalutate.

Eppure permette di:

  • evitare porte pubbliche inutili
  • proteggere database
  • accedere a servizi interni
  • semplificare l’accesso remoto
  • ridurre drasticamente l’esposizione

Spesso vedo setup complicatissimi risolvibili con una singola riga:

ssh -L

E sinceramente continuo a pensare che uno dei principi migliori in ambito sysadmin sia sempre lo stesso:

meno porte aperte, meno problemi.


Le opinioni in quanto tali sono opinabili e nulla ti vieta di approfondire l’argomento.

Risorse: