Making a local web server public with localtunnel

May 11, 2010

These days it’s fairly common to run a local environment for web development. Whether you’re running Apache, Mongrel, or the App Engine SDK, we’re all starting to see the benefits of having a production-like environment right there on your laptop so you can iteratively code and debug your app without deploying live, or even needing the Internet.

However, with the growing popularity of callbacks and webhooks, you can only really debug if your script is live and on the Internet. There are also other cases where you need to make what are normally private and/or local web servers public, such as various kinds of testing or quick public demos. Demos are a surprisingly common case, especially for multi-user systems (“Man, I wish I could have you join this chat room app I’m working on, but it’s only running on my laptop”).

The solution is obvious, right? SSH remote forwarding, or reverse tunneling. Use a magical set of options with SSH with a public server you have SSH access to, and set up a tunnel from that machine to your local machine. When people connect to a port on your public machine, it gets forwarded to a local port on your machine, looking as if that port was on a public IP.

The idea is great, but it’s a hassle to set up. You need to make sure sshd is set up properly in order to make a public tunnel on the remote machine, or you need to set up two tunnels, one from your machine to a private port on the remote machine, and then another on the remote machine from a public port to the private port (that forwards to your machine).

In short, it’s too much of a hassle to consider it a quick and easy option. Here is the quick and easy option:

$ localtunnel 8080

And you’re done! With localtunnel, it’s so simple to set this up, it’s almost fun to do. What’s more is that the publicly accessible URL has a nice hostname and uses port 80, no matter what port its on locally. And it tells you what this URL is when you start localtunnel:

What’s going on behind the scenes is a web server component running on localtunnel.com. It serves two purposes: a virtual host reverse proxy to the port forward, and a tunnel register API (try going to http://open.localtunnel.com). This simple API allocates a port to tunnel on, and gives the localtunnel client command the information it needs to set up an SSH tunnel for you. The localtunnel command just wraps an SSH library and does this register call.

Of course, there’s also the authentication part. As a free, public service, we don’t want to just give everybody SSH access to this machine (as it may seem). The user localtunnel on that box is made just for this service. It has no shell. It only has a home directory with an authorized_keys file. We require you to upload a public key for authentication, and we also mark that key with options that say you can only do port forwarding. Although, it can’t be used for arbitrary port forwarding… because it’s only a private port on the remote side, it can only be used with the special reverse proxy.

So there it is. And the code is on GitHub. You might notice the server is in Python and the client in Ruby. Why? It just made sense. Python has Twisted, which I like for server stuff. And Ruby is great for command line scripts, and has a nice SSH library. In the end, it doesn’t matter what it’s written in. Ultimately it’s a Unix program.

48 Responses to “Making a local web server public with localtunnel”

interesting post. We’re working on a similar project focused on Web services (or Web servers, if you want) running on small devices. Yaler aims to provide a simple, open and scalable relay infrastructure and is implemented with Java non-blocking sockets and hierarchical state machines. For more information, please visit http://yaler.org/

> In short, it’s too much of a hassle to consider it a
> quick and easy option.

SSH reverse tunnel is quick, simple and safe. I would say much simpler than setting up another service on your server and safer than using a 3rd party tunnel. Try this
screen -dmS shinynewtunneltoapache ssh -Nvv -o TCPKeepAlive=yes -R [remote port]:[local IP]:[local port] user@remotemachine

for example
screen -dmS shinynewtunneltoapache ssh -Nvv -o TCPKeepAlive=yes -R 10080:192.168.13.2:80 user@remotemachine
Create an alias if you use it often.

Just make sure you have
GatewayPorts yes
in your sshd config on remotemachine.

Yes, really this is just wrapping SSH reverse tunneling and providing a 3rd party host for you. Since we weren’t optimizing for safety/security of transmitted contents, a 3rd party host makes it much easier, on top of eliminating all the options of SSH to do this. If you were worried about the 3rd party bit, the server is available. Again, it’s just wrapping SSH and everything you’re describing (thanks for sharing btw), so it’s not really different, just more convenient.

No, in fact, I’d like to come up with a good solution for maintaining a persistent tunnel hostname (whether the tunnel is persistent or not). If this turns out to be resource intensive, we’d start limiting it.

Depending on network topologies this might prove difficult. Especially if you’re talking about a webhook scenario where a web app needs to access a script that you only have (or want to have while developing) on your laptop. If you’re behind a NAT, directly connecting would require port forwarding on whatever network you’re on at the time, which may not be possible. Nor is it portable — if I want to go from Starbucks to home to work and use it all three places, that’s three networks I’d have to talk to the network admin to get port forwarding, which is probably not even possible at Starbucks.

Does Local Tunnel work with Python? If not, does anyone have suggestions for the following problem:

I’m working on an app that uses Yahoo OAuth. The OAuth had been working fine but I just registered my domain with Yahoo and now it will not let me use the OAuth when I develop locally because
“Custom port is not allowed or the host is not registered with this consumer key.”

Hmm. Well it works with any language because it’s not a library. It’s a network gateway.

Obviously, Yahoo can’t reach localhost because that’s your local machine. That’s more the issue than the custom port issue (8080) I imagine. If you run localtunnel 8080, it’ll give you a temporary URL that you can give Yahoo that will be on port 80 and should satisfy their requirements.

Hi, I think your blog might be having browser compatibility issues.
When I look at your blog site in Opera, it looks fine
but when opening in Internet Explorer, it has
some overlapping. I just wanted to give you a quick heads up!
Other then that, superb blog!

I’m not sure where you are getting your info, but good topic. I needs to spend some time learning more or understanding more. Thanks for excellent info I was looking for this information for my mission.

Hi there, i read your blog from time to time and i own a similar one and i was just wondering if you get a
lot of spam comments? If so how do you protect
against it, any plugin or anything you can advise?
I get so much lately it’s driving me insane so any help is very much appreciated.

Admiring the persistence you put into your blog and in depth information you provide.
It’s great to come across a blog every once in a while that isn’t the same outdated rehashed information.
Fantastic read! I’ve saved your site and I’m including your RSS feeds to my Google account.

Just desire to say your article is as astonishing.
The clarity on your submit is simply excellent and i could assume
you are a professional on this subject. Fine together with your permission let me to
clutch your RSS feed to stay up to date with drawing close post.
Thanks 1,000,000 and please continue the rewarding work.

Thanks for ones marvelous posting! I genuinely
enjoyed reading it, you can be a great author. I will be
sure to bookmark your blog and definitely will come back down the road.
I want to encourage you to continue your great job,
have a nice weekend!

Admiring the hard work you put into your blog and detailed information you provide.
It’s awesome to come across a blog every once in a while that isn’t
the same old rehashed information. Great read! I’ve saved your site and I’m adding
your RSS feeds to my Google account.

you are really a good webmaster. The website loading speed
is amazing. It kind of feels that you’re doing any distinctive trick.
In addition, The contents are masterwork. you have performed
a great activity in this matter!