Ever had those moments when you realize you were supposed to do some Googling on a given thing, but can’t remember what it was? I just experienced this myself. Then I remembered the thing was reverse SSH tunneling.
So, I needed a way to connect to a Linux box hidden behind a firewall, with no chance of opening any ports to the outside world myself. In my own home network it is trivial to redirect any external port into a given IP address and port on my LAN using my router’s port/address translation (PAT) capability. But when I use a mobile broadband connection, all inbound traffic is just blocked. Should I call my ISP and tell them: “I have this RasPi thing in my car and it’s using mobile broadband and I can’t get to it so please could you open a port for me?”
Maybe not. Reverse SSH Tunnel to the rescue! Let’s assume the following scenario. You have a (Ubuntu 14.04 LTS) laptop on your home network, which can be accessed from the outside world. You have an SSH server running on the default port 22 of the laptop, and you can access that using the external port 3333 of your home router. Your laptop username is vivek and your public IP is xxx.xxx.xxx.xxx. Normally you would connect to this machine with
ssh email@example.com -p 3333
Then you have another, remote laptop, which is on a network with no static IP. All the external ports on that network are blocked as well. Assume your username on that laptop is vivek1. That’s all you need to know.
On the remote laptop, you should (physically) run the following:
ssh -f -N -T -R 9999:localhost:22 firstname.lastname@example.org -p 3333
It prompts for the password for user vivek. After supplied, the command line is returned and it seems like nothing happened. But when you get to your home laptop and run the command
ssh -p 9999 vivek1@localhost
you get prompted for the password for vivek1, and you’re finally connected to the remote laptop! How cool is that?
Figuring out how to make it persistent was a trickier one, but eventually I got it. You should run the following (as root) on the remote laptop:
ssh-keygen -t rsa
Just leave everything blank, and you’ll end up with the .ssh/id_rsa.pub file containing the rsa key, which you would then copy to your home laptop like this:
cat .ssh/id_rsa.pub | ssh email@example.com -p 3333 'cat >> .ssh/authorized_keys'
If the .ssh directory doesn’t exist on your home laptop, create it with:
ssh firstname.lastname@example.org -p 3333 mkdir .ssh
Now you should be able to ssh from the remote laptop (as root) into your home laptop as vivek without a password. Finally, you should put the command that establishes the reverse ssh tunnel into a script which is run at boot on the remote machine. Add the following line into /etc/rc.local (before the exit statement):
/usr/bin/ssh -f -N -T -R 9999:localhost:22 email@example.com -p 3333
As soon as the remote machine boots up, you will be able to connect to it by ssh’ing into port 9999 on your localhost as vivek1. Job well done!