SSH tunnel from the command line

Every once in a while I need to set up a temporary SSH tunnel from one computer to another, possibly via a third one, and can’t be bothered with configuring any of my otherwise frequently used GUI tools ‘SSH Tunnel Manager’ for OS X or ‘SSH Tunnel’ on Win XP. Each time, however, I end up reading the man page for the ssh command or googling for ‘ssh tunnel linux’ or something similar, since I never seem to remember how to set up a simple SSH tunnel on the command line. The ssh man page is especially unhelpful:

-L [bind_address:]port:host:hostport

What? Which port goes where? And what’s the bind_address and hostport? If you read the explanation of the switch you’ll probably just become even more confused. After a few trials and errors I usually get my SSH tunnel up and running, but most of the time I’m not quite sure what I’ve really done.

So here’s a note to self on how to do this once and for all.

The light in the end of the tunnel

Now, the basic idea is that you issue a normal ssh command to the remote host as if you would open a remote shell, and just throw in the -L switch to instruct ssh to forward a separate port at the same time. Say that I’d like to open up a tunnel from the local machine to http://www.fredrikbostrom.net. The base command is

ssh fredrik@www.fredrikbostrom.net

but since I want to set up a tunnel from, say, port 10001 on the local host to port 3689 on the remote host, I need to throw in the -L switch:

ssh -L 10001:localhost:3689 fredrik@www.fredrikbostrom.net

This is where the confusion sets in. Where did that localhost come from? Intuitively you could think that it refers to the local host, i.e. the machine you’re writing that command on (like the command would say “connect from 10001 on localhost to 3689 on http://www.fredrikbostrom.net”), but no. It refers to the host at the remote side which we want to act as the other end of our tunnel. Since in this case we want the tunnel to end at the same host as we logged in to using the base ssh command, we use ‘localhost’. So in natural language, this would say

Start a tunnel from here (where we write the command) on port 10001, then go to http://www.fredrikbostrom.net as user fredrik and end the tunnel at a host called localhost on port 3689 over there.

Every now and then I use the above command to access the Firefly (mt-daapd) web interface running on my server from my laptop when I’m not at home. And since I haven’t forwarded the 3689 port in my ADSL modem, I have to use an SSH tunnel to access it. The above command does just that and when it’s up and running I can type http://locahost:10001 in my browser, which will access port 3689 on my server. To close the tunnel, just log out from the remote host as you normally would when closing the SSH connection.

[ad]

Now what if we change ‘localhost’ to something else? For example, I sometimes want to access the MythWeb web interface of my HTPC when I’m not at home. Again, since I haven’t got a forward up and running from my ADSL modem to my HTPC, I have to use an SSH tunnel. This is easily achieved by changing ‘localhost’ in the above command to the hostname of the HTPC:

ssh -L 10001:kermit:80 fredrik@www.fredrikbostrom.net

Again, in natural language, this would say

Start a tunnel from here (where the command is issued) on port 10001, then go to http://www.fredrikbostrom.net as user fredrik and end the tunnel at a host named ‘kermit’ on port 80 over there.

This requires the host kermit to be available in the same local network as the machine you logged in to. If you try to forward to a host not in the same local network, you’ll probably get an error message like

channel 2: open failed: administratively prohibited: open failed.

As I haven’t got any deeper understanding of how the tunneling mechanism actually works, I can’t really say why you can’t do this, but on the other hand, why would you want to?

‘Local’ tunnels

What then, if you want to open up a tunnel within your local network, when you don’t have a ‘remote side’ per se? In this case you actually have two options. If the local host runs an SSH server, you can ssh into your localhost and make the tunnel end at the final destination host

ssh -L 10001:kermit:80 fredrik@localhost

That’s the command I would use to open up a tunnel from my server (port 10001) to the HTPC (port 80) while in a shell on the server. This is possible since the server (now the local host) runs an SSH server that I can log in to. It might however seem awkward since I essentially open up an SSH shell connection to the same computer I’m issuing the command on, and the tunnel to kermit is created sort of as an invisible ‘side-effect’.

[ad]

The other option comes in handy when the local host doesn’t have an SSH server running. This command is exactly the same as the first tunnel command we saw, namely

ssh -L 10001:localhost:80 fredrik@kermit

If issued on my laptop while I’m at home, this would open up a tunnel from port 10001 on my laptop to port 80 on my HTPC. And in this case, I would end up in a shell on kermit.

Send your stooges to dig the tunnel

As mentioned above, these commands not only create a tunnel to the desired end machine, they also open up a normal shell connection to the remote host as they would without the -L switch. This is convenient if you don’t need your local shell or want to do some work at the remote side while you’re at it, since you can close the tunnel just by logging out from the remote side.

If, however, you need your local shell and can’t be bothered opening a new terminal or for some other reason would just want to open up the tunnel and forget about it, you can send it to the background using the -f and -N switches in addition to the -L switch.

ssh -fNL 10001:kermit:80 fredrik@www.fredrikbostrom.net

This will not open the remote shell but instead send the tunnel process to the background. The downside is that you’ll have to look up the process and kill it manually when you want to close the tunnel.

Advertisements

10 Comments

Filed under Geek speak, Linux, Mac

10 responses to “SSH tunnel from the command line

  1. Jay

    Thanks for the post, it’s informative. I feel like the nuggets of information you’ve provided should help me solve my problem but I’m not quite sure how. My problem? I’m stuck in a hospital that restricts everything except web surfing. I want to be able to do everything I would normally do at home (email with Mail.app, games, IM, maybe even torrents). I’ve found the application Proxifier, which seems to do most of the magic, but I need to connect it to somewhere, can an SSH tunnel serve this purpose?

    • Thanks for your comment! What you’re after would probably require some sort of VPN solution, and unfortunately I’m not (yet) that familiar with VPNs so I really can’t help you on that one.

  2. Tejvan

    Finally a decent explanation of the ssh command tunnel command line! My life is now complete. Thank you.

  3. Liza

    At last, bright light at the end of the tunnel. Thanks so much for sharing Fredrik!

  4. Pingback: SSH-getunnelter Datenbankzugang für gehostete LAMP-Server – I | linux-blog – Fa. anracon – Dr. Mönchmeyer

  5. Rosé

    Thanks for describtion is realy useful

  6. gdbtek

    I wrote this tool https://github.com/gdbtek/ssh-tunneling and hope it helps. It supports local/remote tunnel.

  7. Jim

    Nice. A well written article. And you are right about the man page.

  8. Pingback: Pocket Full of SSH Forwarding Tricks | petes-brain

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s