Skip to content

Instantly share code, notes, and snippets.

@rfairley
Last active May 21, 2024 08:57
Show Gist options
  • Save rfairley/41f4a8e8b4c13f19d748ba4b0e600cc5 to your computer and use it in GitHub Desktop.
Save rfairley/41f4a8e8b4c13f19d748ba4b0e600cc5 to your computer and use it in GitHub Desktop.
Connecting to a Raspberry Pi through a VPS using a reverse SSH tunnel

Connecting to a Raspberry Pi through a VPS using a reverse SSH tunnel

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.

  1. 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 the authorized_keys file does not exist, create it. To find the public SSH key of your user on your laptop, run cat ~/.ssh/id_rsa.pub, and copy the output. If that file does not exist, then run ssh-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.
  2. 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 the pi user is raspberry.
  3. 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).
  4. 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.
  5. 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).
  6. 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/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment