There are many posts on the Internet with instructions to set up SSH tunnels. However, the tutorials I found described either ways to:
- forward HTTP and other protocols from a firewalled machine through one that is not firewalled,
- or forward ports on the inside of the firewall (that aren’t supposed to be accessible outside of it) through an SSH tunnel to allow access from outside of the firewall.
What I didn’t find, was instructions on using SSH tunnels to allow me to SSH from a non-firewalled machine to one that is behind a firewall and NAT.
The short solution is to run sshd on the firewalled machine, and use the second method to forward the ports on localhost to a remote machine.
To do this requires setting up a reverse SSH tunnel. In short, the firewalled machine will SSH to the non-firewalled machine, and expose a port on that machine that the non-firewalled machine can SSH to. SSH’ing to the new port will create an SSH connection to the firewalled machine’s SSHD.
In my particular case, the firewalled machine was running Windows, so Cygwin was used with OpenSSH. The non-firewalled machine was running Ubuntu 11.10 Oneiric Ocelot.
Detailed instructions follow:
First, install Cygwin on the firewalled machine. Cygwin can be downloaded from http://www.cygwin.com/. When installing Cygwin, it will ask what packages you want to install. You will need OpenSSH, which is not enabled by default. Navigate to the package (it’s under Net) or search for it, and click the text “skip” to change it to a version number. Then click next to continue the installation.
After installing Cygwin, you may want to add Cygwin’s bin directory to your PATH. The rest of the examples in this tutorial assume you have done so.
Next you will need to configure SSHD on the firewalled machine, and start it. From Cygwin’s bash command prompt, enter the following:
ssh-host-config -y cygrunsrv -S sshd
I followed the instructions at Noah’s SSHD HowTo to do this step. That site also provides a fix for an error that you may get. I did not get the error initially, but I reinstalled Cygwin and it came up that time. The solution on that page worked for me.
Test SSH to localhost
To ensure that SSHD is up and running on the firewalled machine, ssh to localhost from the firewalled machine’s Cygwin bash:
If SSHD is working, you will be able to connect to the firewalled machine’s SSHD from the firewalled machine.
Test SSH to the non-firewalled machine
To ensure that you can connect out from the firewalled machine to the non-firewalled machine, ssh to the non-firewalled machine’s external IP:
You need to be able to ssh to the non-firewalled machine in order to set up the reverse tunnel.
Set up the reverse tunnel
To set up the tunnel itself, I followed the instructions on HowToForge’s Reverse SSH Tunneling article.
From the firewalled machine’s Cygwin bash prompt, run:
ssh -R 19999:localhost:22 firstname.lastname@example.org
Where 19999 is the port to set up on the non-firewalled machine, and 22 is the port on localhost to route the connection to. If the connection ever times out, the tunnel will be broken, so you need to keep the connection alive. You can run top to keep the connection alive.
Once that is connected, you can ssh to the firewalled machine from the non-firewalled machine by running:
ssh firewalledmachineuser@localhost -p 19999
Other SSH-based services like sshfs can also be used through the tunnel. You may also want to run SSH without any standard input or commands running:
ssh -nNT -R 19999:localhost:22 email@example.com
or if you want to run it in the background:
ssh -fnNT -R 19999:localhost:22 firstname.lastname@example.org
These two options seem to keep alive by themselves, but I am not sure if it is guaranteed that they will. There are various keep-alive tricks described in the comments of a blog post on The Mad Philosopher. My preferred solution is to put
ServerAliveInterval 60 ServerAliveCountMax 9999