How to Create a Reverse SSH Tunnel
Introduction
Oftentimes, a remote device needs to be accessed through SSH
but it's not reachable due to network conditions, security requirements, etc.
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.
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:
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
Keys naming You can use any names you want for your keys, we are just using remote and local for convinience. |
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
Key copying The commands above work if you have a way of placing the key inside each other device. If it's not possible, you can also just copy the raw text from the .pub file and paste it into the required file as a new line. |
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
Set the User Remember to set the User variable in the service file. Also notice the script called reverse-ssh.sh , we will create it right away. |
- 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
Set the LOCAL info Remember to set LOCAL_USER as the user from the LOCAL device, and LOCAL_IP as the IP of the LOCAL device too. Ideally, this IP should be static, so that you don't need to change this in case the IP changes. Also, you can just use a DNS instead of the IP (ex. mydomain.com). |
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
REMOTE User Replace REMOTE_USER with the User's name that is running the tunnel on the REMOTE side. |