February 9th, 2009

How to setup a reverse ssh tunnel

Ok, so most of us know how to set up your standard SSH tunnel; when you create a secure link between a local port and a port on a remote box. Now recently I had to need to forward a port on a remote server to a local port on my laptop, which is behind a firewall. Turns out SSH can do this too. Check it out:

ssh -nNT -R 9867:localhost:3000 kcbanner@caseybanner.ca

What does this do? Lets look on my server, a quick netstat -l show us:

tcp        0      0 caseybanner.ca:9867 *:*                         LISTEN

Ok, so my server is listening on port 9867 for incoming connections. Let's test the bridge: I start netcat on my laptop, to listen to port 3000:

nc -l -p 3000

And on the server I run:

curl localhost:9867

And voila! Netcat on my local host prints out some http headers. Ok, so we have a bridge setup and everything is working. Except on the server, ssh has bound 9867 to the loopback address only, so remote hosts can't connect. You have to have a line in your /etc/ssh/sshd_config file like this:

GatewayPorts clientspecified

This allows you to bind to more than just the local interface. We also have to change our original command to:

ssh -nNT -R :9867:localhost:3000 kcbanner@caseybanner.ca

Note the added ':' in front of the 9867, this is the "bind address", and when its empty (and GatewayPorts is set to 'clientspecified', or 'on'), this will bind to all address on the remote server. You can also add '-f' to the list of options to make ssh go into the background.I find this usefull when developing facebook apps with rails. I can forward a port on my server to my laptop (behind a firewall), and tell facebook my app is on my server, when really its on my laptop. Very handy.