A private host behind NAT may be able to connect outward while remaining unreachable from the internet. A reverse SSH tunnel uses that outbound connection to create a listener on a relay you control. It is useful for authorized remote administration when a VPN or ordinary inbound route is unavailable.
Draw the two endpoints before typing the command
In this example, the private machine runs SSH on its own loopback port 22. It connects to a relay called relay.example.com. The relay receives a new listener on its loopback port 2222. Those example names and ports should be replaced with your approved endpoints.
Private host:127.0.0.1:22
← encrypted outbound SSH connection →
Relay:127.0.0.1:2222Verify the private SSH service locally, then verify ordinary key-based login to the relay. Check host-key fingerprints through a trusted channel. Forwarding does not replace authentication to either machine.
Create a loopback-bound reverse listener
ssh -NT \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-R 127.0.0.1:2222:127.0.0.1:22 \
tunneluser@relay.example.com-N runs no remote command, and -T avoids allocating a terminal. The first address and port describe the listener on the relay. The second describe the destination reached from the private host. ExitOnForwardFailure reports a listener setup failure; it does not prove the eventual destination service is reachable.
Keep the server’s GatewayPorts setting at its default no for this design. A server configured to force wildcard bindings can defeat the intended exposure boundary. Verify the actual listener rather than relying on the command’s appearance.
Connect through the relay
From an authenticated shell on the relay, the forwarded private SSH service is reached through this command:
ssh -p 2222 privateuser@127.0.0.1To use a workstation without leaving a shell on the relay, create a local forward from the workstation to the relay’s listener:
ssh -NT -L 127.0.0.1:2223:127.0.0.1:2222 admin@relay.example.comThen, from another workstation terminal:
ssh -p 2223 privateuser@127.0.0.1The private host’s SSH authentication still applies. The relay’s loopback listener is reachable by local processes and users on the relay, so a shared relay is a separate trust decision.
Diagnose listener, policy, and destination independently
ss -ltn | rg ":2222"
# On the private host, add -v to inspect SSH negotiation:
ssh -v -NT -R 127.0.0.1:2222:127.0.0.1:22 tunneluser@relay.example.comRun the listener check on the relay. A setup refusal may mean the port is already occupied or the relay denies remote forwarding. Review effective sshd settings, account restrictions, AllowTcpForwarding, PermitListen, and DisableForwarding. If the listener exists but the connection fails, check the private service and its authentication logs.
Keep diagnostic output private until hostnames, users, and addresses are sanitized. Avoid disabling host-key checks to silence a warning; investigate an unexpected key change.
Add persistence after the manual path works
Use a dedicated tunnel account and key with only the required forwarding permissions. For an unattended deployment, a service manager or autossh can reconnect, but first verify key authentication, host-key trust, policy restrictions, and the command in the foreground. Persistence can otherwise hide repeated failures.
Test a controlled network interruption and verify the listener returns without creating duplicates. Remove the relay listener when the tunnel stops. Keep ordinary SSH security controls in place, and record who owns the relay and forwarded service so the access path remains understandable.