SSH (Secure Shell) to a host existing in an internal network through a reverse-tunneled SSH connection to an externally accessible VPS (Virtual Private Server). This setup is described where the internal host is a Raspberry Pi, but can be generalized for any host on the internal network that runs an OpenSSH server.
internal network Internet home network
|| ||
------------------ || ------------------ || ------------------
| | reverse SSH tunnel (VPS $tunnel_port to Pi port 22) | | || | |
| Raspberry Pi ==================================================> VPS =======================> laptop (client) |
| internal IP <================================================== public IP $vps_ip <======================= |
| | || | | SSH to VPS $tunnel_port | |
------------------ || ------------------ || ------------------
|| ||
$tunnel_port
- port on the VPS where traffic is forwarded to the Pi$vps_ip
- public IP address or domain name of the VPS$vps_user
- user that you have access to on the VPS (e.g.root
)
This assumes you are running Linux or macOS on your laptop and using the OpenSSH client, and that the VPS is running an OpenSSH server on Linux.
To log into the Pi in steps 2 and 5, you'll need be on the same internal network as the Pi or have access to the HDMI display of the Pi.
- Log into the VPS, and add the public SSH key of your user on your laptop to its own line in
/home/$vps_user/.ssh/authorized_keys
. If theauthorized_keys
file does not exist, create it. To find the public SSH key of your user on your laptop, runcat ~/.ssh/id_rsa.pub
, and copy the output. If that file does not exist, then runssh-keygen
to generate a new private/public SSH key pair. This step might have been completed already if you set up your VPS with your SSH key; otherwise your VPS will likely prompt for a password when logging in. - Log into the Pi, and add the public SSH key of your user on your laptop to its own line in
/home/pi/.ssh/authorized_keys
(same instructions as step 1 apply). By default, the password to log into thepi
user israspberry
. - Log into the VPS, and add the public SSH key of the
pi
user on the Pi to its own line in/home/$vps_user/.ssh/authorized_keys
(same instructions as step 1 apply). - On the VPS: configure the SSH server by adding
GatewayPorts yes
on its own line in/etc/ssh/sshd_config
. Then,systemctl reload sshd.service
. Editing this file requires root access. - On the Pi:
ssh -R $tunnel_port:localhost:22 $vps_user@$vps_ip
. This instructs the VPS to forward any connections to$tunnel_port
on the VPS to port 22 on the Pi (port 22 is the default port for SSH). - From your laptop:
ssh -p $tunnel_port pi@$vps_ip
. This uses the reverse-tunneled SSH connection between the Pi and the VPS to connect the your laptop to the Pi. Now you can execute commands on the Pi without being in the same internal network!
In practice, the command in step 5 should be run as a service that starts when the Pi boots up, and restarts if the command exits, in order to keep the tunneled connection active. This can be done using a systemd service unit.
Note: port $tunnel_port
can be any unused and open port on the VPS that $vps_user
has access to (make sure the port is open in the appropriate firewall otherwise the connection will time out).
To extend this, one could connect to a VNC server on the Pi through the reverse SSH tunnel by forwarding to e.g. port 5900
instead of 22
. This would look like: ssh -R $tunnel_port:localhost:5900 $vps_user@$vps_ip
.
Based on: https://www.maketecheasier.com/reverse-ssh-tunnel-allow-external-connections/