SSH Tunnels

ssh unix

Fri Dec 28 22:39:00 -0800 2007

And now for one of my favorite bits of black magic from the unix poweruser’s toolkit: ssh tunnels.

Like most good tricks, this one is simple. It lets you bounce TCP traffic through an ssh connection. This is handy in a variety of situations, but the one I’ve used it most often for is to access a website which is available only inside of a corporate LAN. If you’ve got external ssh access, you can set up a tunnel that will let you point your browser at a local port to access that site.

The syntax is:

ssh -L [local_port]:[site_you_want_to_reach]:[remote_port] [ssh_host] [command]

This can be a little confusing, but there’s actually only two variables that matter. So first I’ll fill in the defaults you’ll probably always want to use:

ssh -L 9999:[site_you_want_to_reach]:80 [ssh_host] "sleep 9000"

Much better. Now we just need to know the site we want to go to, and the host we will tunnel it through. For example, let’s say we want to view RubyInside, but tunneled through your remote server example.com:

ssh -L 9999:rubyinside.com:80 user@example.com "sleep 9000"

You can now browse to http://localhost:9999/ and see RubyInside. (This won’t work if the remote site uses named virtual hosts. You can rememdy this by adding the hostname (like rubyinside.com) to your /etc/hosts as an alias for localhost, and then point your browser to http://rubyinside.com:9999/.)

Since RubyInside is public, this example is not actually useful - but now that you see how it works, let’s look at how it can be used to view a Rails app running inside a LAN on someone’s workstation. Let’s say the mongrel is running on port 3000 and that the workstation is devbox.localnet, but devbox.localnet is only accessible from your ssh bouncepoint, which we’ll call bouncepoint.example.com.

ssh -L 9999:devbox.localnet:3000 user@bouncepoint.example.com "sleep 9000"

ssh tunnels can also be used to bypass those silly content filters that some companies insist on installing on their local LANs. This trick requires that you be able to send outgoing TCP traffic, and you have a remote ssh server listening outside the LAN. (If port 22 is blocked, you’ll need to find one that isn’t, and then get your remote ssh server to listen on that port.) By tunneling all your web traffic through ssh, you can bypass any content filters - and also get a completely secure connection that is impossible to easedrop on.

For example, if you wanted to view the latest Penny Arcade comic, but found that the client site you’re working on for the day blocks it, you might use your remote VPS host to set up a tunnel like this:

ssh -L 9999:penny-arcade.com:80 vpsuser@vpshost.com "sleep 9000"

One final note: if you’re wondering what the sleep 9000 is for. ssh requires a command, and when the command is done executing, it exits. So you have to give a command that will stall. I use 9000 because it’s plenty long and easy to type. (When you’re done, just hitting Ctrl-C in the terminal that’s running the tunnel will close it.) But if you wanted it to last indefintely, you could use while [ 1 ]; do sleep 100; done.