SSH reverse tunnel
Written by masteryeti 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 0.0.0.0:[remote-port]:127.0.0.1:[local-port] [remote-user]@[remote-host] -p [remote-ssh-listen-port]
-
-o 'ExitOnForwardFailure yes'
ensures the command will terminate upon any error in forwarding. -
-N
means no command line (shell) will be opened. -
-R 0.0.0.0:[remote-port]:127.0.0.1:[local-port]
makes the local port publicly (at0.0.0.0
, or privately using127.0.0.1
) available at the given remote port. Be sure the port is allowed through the firewall if it must be publicly available. -
[remote-user]@[remote-host] -p [remote-ssh-listen-port]
define the ssh login details of a user on the remote server. By default, the port is 22, and may be left out if that is the port sshd is running on.
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 0.0.0.0:22001 0.0.0.0:22002 0.0.0.0:22003 0.0.0.0:22004 0.0.0.0:22005 0.0.0.0:22006 0.0.0.0:22007 0.0.0.0:22008 0.0.0.0:22009 127.0.0.1:22001 127.0.0.1:22002 127.0.0.1:22003 127.0.0.1:22004 127.0.0.1:22005 127.0.0.1:22006 127.0.0.1:22007 127.0.0.1:22008 127.0.0.1:22009
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/id_rsa.pub
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 127.0.0.1:22001:127.0.0.1:[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 127.0.0.1:[local-port]:127.0.0.1:22001 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 0.0.0.0:22001
instead of 127.0.0.1:22001
in the remote address.
This means that anyone who can access the remote machine port, has access to the endpoint of that tunnel.