Cater Hero

SSH Tunneling with -L

May 16th 2011

Well hello.. this is my first blog post from my new iPad.. I ssh’d into my server using Prompt, hopped onto my blogging/projects VM, typed rake new, fired up VIM, and away we go.. tonight I want to share a nugget of information that took me the better part of a week to figure out: how to ssh tunnel using -L.

So to be honest, I’m new at living on the CLI, but I love it. Recently my co-worker Daniel showed me how to forward a remote webserver to my localhost using ssh; pretty badass and useful IMO. The syntax is simple:

ssh -L localport:localhost:remoteport remoteserver.


Let me explain this in a bit more detail.

Say you’re running a webserver/service on a local or remote VM and you want to debug it locally since the VM is headless and you want to see your work in a browser. Use ssh -L. My dev machine set up is a headless CentOS VM, which is configured to be as similar to my production VM as possible. In order for me to run my code and test things out, I need to view it locally in my browser, with ssh -L I can.

Breaking it out it looks like this:

  • localhost = my windows desktop
  • remote server = a VM running inside VirtualBox (on my desktop)
  • local port: 80
  • remote port: 80

so typing ssh -f -N -L 80:localhost:80 dev-vm will do the following:

  • -f = fork process into backgroundi
  • -N = don't run any commands remotely (w/o this -f will complain)
  • -L = bind the remote and local port to a secure channel

Lets go one step deeper and talk about security concerns we can subvert/enhance with the use of ssh -L.

Now it is great that I can see a webpage, but in my little application I’m doing a few API calls on to a server on ports that aren’t open on my firewall. Oh me oh my, how will I ever get anything done? I could call up my hosting provider and tell them to open up a port here and there, but at home I have a dynamic IP and I don’t want to start poking holes in the firewall rules.

A better option is to tunnel through my remote VM at my hosting provider, which has access to the ports I need, and access the services I need from there. Now you may be thinking, “well you really shouldn’t subvert the security measures put in place by blocking those ports” that is a valid point. However, I believe it is better to use only what you need to get the job done. One way in - one way out, through the single, secure remote VM at the hosting provider.

To illustrate a working example, let’s take this scenario: script.sh is making two calls to an API on Server A, one call goes to port 8000, the other 8443. To your dismay, both of these ports are blocked on your local network. Further, these two ports are also blocked from any traffic not coming from sanctioned IPs. Luckily, your work server, Server B is allowed to interface with Server A, and you can ssh into Server B. Problem solved, see ASCII art below for explaination.

ssh -f -N -L 8000:serverA:8000 -L 8443:serverA:8443 serverB

  • L = localhost
  • A = serverA
  • B = serverB

L —8000/8443—> B —8000/8443—> A
<---8000/8443--- B <---8000/8443--- A
Now, there is one nuance which is what hung me up for a bit. Notice in my first example I was doing 80:localhost:80 dev-vm. That bound a remote web server to my localhost’s port 80. This situation is tunneling traffic on my localhost’s 8000/8443 ports to another ‘liberated’ machine, which does not have the ports blocked. So, what are really saying is, any request locally to Server A on port 8000 or 8443 must go through Server B. To get this to work properly, we need to modify our /etc/hosts file.

In this final step, we will tell our hosts file to take any request to Server A, and forward it to our localhost (127.0.0.1). So in your hosts file, add or modify the following line:

127.0.0.1 localhost

to:

127.0.0.1 localhost serverA

This will route all requests to Server A through the correct ports on Server B.

That’s all for now, next post I’ll go into my local VM set up in some detail. It may be helpful for those of you out there that are forced to use Windows at work and want to replicate your production environment locally.

P.S. I switched over to my laptop…typing on the iPad isn’t so great when you want to keep speed. Maybe it will be better if I do it with my wireless keyboard.

UPDATE: fixed syntax on compound ssh command - replaced ‘serverB’ in the middle with -L.

blog comments powered by Disqus