How to Create a Reverse SSH Tunnel

From RidgeRun Developer Wiki

Introduction

Oftentimes, a remote device needs to be accessed through SSH but it's not reachable due to network conditions, security requirements, etc.

SSH Connection Blocked

A reverse SSH tunnel is a solution to that problem. Basically, the hard-to-reach device will create a tunnel to a specific device that we have access to. From now on, we will use the following notation:

  • LOCAL Device
The device to which we have easy access (your laptop, for example).
  • REMOTE Device
The device that is hard to access (usually it's far away from us, or it's someone else's device).

The following diagram represents the LOCAL device to the left, the REMOTE device to the right, and the tunnel enabling the connection.


SSH Reverse Tunnel Diagram

The tunnel is created by the REMOTE device, and the LOCAL device uses that tunnel to access the REMOTE. Then, to create the tunnel, you need some level of access to the REMOTE device, but this process is done only once, whether you need to move to the REMOTE or you need the REMOTE owner's help.

Instructions

You will find below the instructions to create a reverse SSH tunnel.

Overview

We are going to create the connection based on the following structure:

Reverse SSH Tunnel Block Diagram with Ports

Basically, the tunnel can be achieved in two steps:

  • Step 1: the remote device will create an ssh connection with the local device. It will tell ssh to forward connections from 2210 to port 22, enabling the reverse tunnel.
  • Step 2: the local device has now a tunnel to access the remote device.

All the details are shown below.

Generate Key Pairs (REMOTE and LOCAL)

  • On REMOTE
ssh-keygen -f /home/$USER/.ssh/id_rsa_remote
  • On LOCAL
ssh-keygen -f /home/$USER/.ssh/id_rsa_local


Share Generated Public Keys

We will share the public keys between both devices, so that no password is required when enabling the connections.

  • Copy the LOCAL's public key into the REMOTE's authorized_keys file.
cat id_rsa_local.pub >> ~/.ssh/authorized_keys
  • Copy the REMOTE's public key into the LOCAL's authorized_keys file.
cat id_rsa_remote.pub >> ~/.ssh/authorized_keys


Systemd Service (REMOTE)

We want the REMOTE to enable the tunnel every time it starts. Also, it will try to enable the tunnel if there's an error.

For this we'll create a systemd service running on the REMOTE.

  • Create the file /etc/systemd/system/reverse_ssh.service with the following contents:
[Unit]
Description=Reverse SSH Tunnel Example

[Service]
# Please replace "user" with the REMOTE's username
User=user
Type=simple
ExecStart=/bin/bash /usr/local/bin/reverse-ssh.sh
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target


  • Create the script file /usr/local/bin/reverse-ssh.sh with the content:
DATE=`date '+%Y-%m-%d %H:%M:%S'`
echo "Reverse SSH started at ${DATE}" | systemd-cat -p info

ssh -i /home/$USER/.ssh/id_rsa_remote -oStrictHostKeyChecking=no -N -R 2210:localhost:22 LOCAL_USER@LOCAL_IP


And finally, start the service and enable it so that it starts on every boot.

sudo systemctl daemon-reload
sudo systemctl start reverse_ssh.service
sudo systemctl enable reverse_ssh.service

Enable SSH (LOCAL)

  • Start the ssh service:
sudo service ssh start

SSH Access (LOCAL)

We are all set!

Access the REMOTE with:

ssh -i ~/.ssh/id_rsa_local -p 2210 REMOTE_USER@localhost