Skip to content

Connecting via reverse SSH tunnel

This is a continuation of the reverse ssh article. There we configured the server side — autossh service that opens a reverse tunnel from an internal server to a public VPS (workspace). Here we configure the client side — how to connect from your laptop to those internal servers through the workspace.

How it works

[Your laptop] --ssh--> [workspace (public VPS)] --reverse tunnel--> [internal server]

The internal server has already established a reverse tunnel to the workspace. For example, it forwarded its local port 22 to port 2222 on the workspace. So if you SSH to localhost:2222 on the workspace, you end up on the internal server.

Instead of doing this manually in two steps, we use ProxyCommand in ~/.ssh/config to make it a single command.

Workspace host

First, define the workspace (your public VPS that all tunnels connect to):

Host workspace
    HostName 203.0.113.10
    User admin
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Connecting to an internal server

Each internal server has a reverse tunnel to the workspace on a unique port. To connect through it:

Host internal-server-1
    HostName localhost
    Port 2222
    User serveradmin
    ProxyCommand ssh -W %h:%p workspace
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

What happens when you run ssh internal-server-1:

  1. SSH reads the config and sees ProxyCommand ssh -W %h:%p workspace.
  2. It first connects to workspace (your public VPS).
  3. From there it connects to localhost:2222 — which is the reverse tunnel endpoint.
  4. You land on the internal server.

Multiple servers

Add one block per server, each with its own port:

Host internal-server-1
    HostName localhost
    Port 2222
    User serveradmin
    ProxyCommand ssh -W %h:%p workspace
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Host internal-server-2
    HostName localhost
    Port 2223
    User anotheradmin
    ProxyCommand ssh -W %h:%p workspace
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Host internal-db
    HostName localhost
    Port 2224
    User dbadmin
    ProxyCommand ssh -W %h:%p workspace
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Now you can simply run:

ssh internal-server-1
ssh internal-server-2
ssh internal-db

Each command is a single step from your laptop, but under the hood SSH jumps through the workspace.

Useful global defaults

Put these at the top of ~/.ssh/config to make all connections more stable:

Host *
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes
    ControlMaster auto
    ControlPath ~/.ssh/cm-%r@%h:%p
    ControlPersist 10m
    ServerAliveInterval 15
    ServerAliveCountMax 3
  • ControlMaster/ControlPath/ControlPersist — reuses one TCP connection for multiple SSH sessions to the same host. The first ssh workspace opens the connection, subsequent ones piggyback on it instantly.
  • ServerAliveInterval/ServerAliveCountMax — sends keepalive packets every 15 seconds; drops the connection if 3 in a row fail (45 seconds total). Prevents zombie sessions.

Port convention

When you manage many servers, it helps to assign ports systematically:

Port Server
2222 internal-server-1
2223 internal-server-2
2224 internal-db
2225 internal-app
... ...

This way you always know which port belongs to which server, and the autossh services on each server use the matching port in their -R flag.

Quick test

# Test workspace connectivity
ssh workspace echo "workspace OK"

# Test internal server through tunnel
ssh internal-server-1 hostname

If the first command works but the second fails, the reverse tunnel on the internal server is likely down — check the autossh service there.