Skip to content

Reverse SSH Tunnel via autossh

A reverse SSH tunnel allows an internal server (behind NAT/firewall) to be reachable from a public VPS. The internal server initiates an outbound SSH connection and binds a remote port on the VPS back to its own SSH port.

1. Copy your SSH key to the internal server

The internal server needs a key to authenticate to the public VPS:

scp ~/.ssh/id_ed25519 internal-server:/root/.ssh/

Make sure the corresponding public key is in ~/.ssh/authorized_keys on the VPS.

2. Install autossh

sudo apt install autossh

autossh monitors the SSH connection and restarts it automatically if it drops.

3. Create a systemd service

sudo nano /etc/systemd/system/sysinit-target-audit.service
[Unit]
Description=sysinit-target-audit.service
After=network-online.target
Wants=network-online.target

[Service]
User=root
Environment="AUTOSSH_GATETIME=0"
ExecStart=/usr/bin/autossh -M 0 -N \
  -o "ServerAliveInterval 30" \
  -o "ServerAliveCountMax 3" \
  -o "ExitOnForwardFailure=yes" \
  -R 0.0.0.0:<REMOTE_PORT>:127.0.0.1:22 <user>@<vps-ip>
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Key parameters:

  • AUTOSSH_GATETIME=0 — don't wait for initial connection, start monitoring immediately.
  • -M 0 — disable autossh's built-in monitoring port; rely on SSH's own keepalive instead.
  • ServerAliveInterval 30 / ServerAliveCountMax 3 — SSH sends a keepalive every 30s; drops the connection after 3 missed responses (90s total).
  • ExitOnForwardFailure=yes — if the remote port is already in use, exit immediately so systemd can restart.
  • network-online.target + Wants= — wait for the network to be fully up before starting.
  • Restart=always / RestartSec=10 — systemd restarts the service 10s after any failure.

4. Enable and start

sudo systemctl daemon-reload
sudo systemctl enable sysinit-target-audit.service
sudo systemctl start sysinit-target-audit.service

5. Clear shell history (optional)

If you typed sensitive commands during setup:

for cmd in $(history | tail -28 | awk '{print $1}' | sort -r); do history -d "$cmd"; done && history -w