SSH reverse tunnel

Written by on .

This article demonstrates how to make a local port available on a remote server. Ideal for dynamic IP-addresses or devices not accessible from outside a local network.

Quick reverse tunnel

Further below is a more standardized method using a dedicated tunnel-user. But this following command should already work out of the box (if no root access to the remote server):

ssh -o 'ExitOnForwardFailure yes' -N -R[remote-port]:[local-port] [remote-user]@[remote-host] -p [remote-ssh-listen-port]

Remote server configuration

It is good to stick to the following standardized setup. First add a new dummy-user that will only be used for authentication purposes (will have no home-directory).

useradd --no-create-home -s /bin/false tunnel

Add the following to /etc/ssh/sshd_config:

Port 22000 Match User tunnel PasswordAuthentication no AuthorizedKeysFile /etc/ssh/tunnel_keys GatewayPorts clientspecified AllowTcpForwarding yes PermitOpen X11Forwarding no AllowAgentForwarding no ForceCommand /bin/false PermitTTY no

Ensure a file exists (which only root may write to), with on each line the public key of the user who is allowed to create a tunnel. That is, to allow a user, add the contents of the user's ~/.ssh/ file to /etc/ssh/tunnel_keys:

ssh-rsa ... user@device-name

Open the tunnel-ports in the firewall:

firewall-cmd --add-port=22000-22009/tcp --permanent firewall-cmd --reload firewall-cmd --list-all

Note: Don't forget to forward these ports to the remote machine if it's behind a proxy (in TCP-mode).

Creating the reverse SSH-tunnel (actual usage)

ssh -o 'ExitOnForwardFailure yes' -N -R[local-port] tunnel@[remote-host] -p 22000

The above command will keep running until interrupted, an error occurred, or it is killed. To stop the command gracefully, use <CTRL+C>. This command does not terminate if a connection between the remote and local port was disconnected or stopped listening. That is, it will keep the tunnel intact, and survives a restart of a program listening on the local-port.

You may make the tunnel available on another machine, using the following command on that other machine:

ssh -o 'ExitOnForwardFailure yes' -N -L[local-port]: tunnel@[remote-host] -p 22000

These tunnels are only (privately) available for the given tunnel user and all in the allocated port range as per the configuration. But by default, anyone with shell-access to the server typically has access to the tunnels.

If you wish to make the tunnel public, use instead of in the remote address. This means that anyone who can access the remote machine port, has access to the endpoint of that tunnel.