♾️🧞‍♀️✨ — Using SSH tunnels to deploy your site

01 Jan 2019

Running a local service on the open Internet is still a thing, even in the age of the Cloud.

For instance, I have a local set of dashboards using Corsica that I’d like to have access to from the road. You may want to show a client work in progress without having to bother with deploying to an external host. You may want to connect to a security camera you run attached to a Raspberry Pi. Or run a web application on a non-privileged port.

For a long time, the way to do that would had been to set up port-forwarding on your router and use a personal DNS service. Port-forwarding requires router configuration, and limits you to exposing one service to the web, and your ISP most likely blocks ports 80 and 443.

With an SSH tunnel, you can expose your service to the internet without the hassle of router configuration:

ssh -R 80:localhost:8080 external.example.com

Your service at localhost:8080 would be on the web at http://external.example.com.

The host external.example.com needs to be reachable from the public internet. You could host your endpoint yourself in the Cloud, but endpoints for SSH tunnels are available as a service from several providers.

Serveo

Serveo’s port-forwarding service is free-as-in-beer. It’s offered by its creator, @trevordixon. To use it for a service running on port 3000 run the command:

ssh -R 80:localhost:3000 serveo.net

which will return:

Hi there
Forwarding HTTP traffic from https://randomname.serveo.net
Press g to start a GUI session and ctrl-c to quit.

Notice that resulting url is https so you don’t have to set up your own certificates.

You can specify a sub-domain, in your ssh command.

ssh -R emma:80:localhost:8888 serveo.net

If the subdomain emma was available, you’d be reachable at https://emma.serveo.net.

Using a tool like autossh and startup scripts, you can make sure your service lives between restarts. Remember that you’ll also need to start the service you’re tunnelling. There’s a whole post on setting up autossh with systemd you which is useful here.

Serveo’s ease-of-use is also its flaw. Anyone can set up a forward with it, and the serveo.net certificate is a wild card, so if a browser trusts your service using Serveo, it trusts every other service using it to forward.

Pagekite

Pagekite’s service is similar to Serveo, but other than a free-trial period, is paid. The company calls the tunnels ‘kites’ and meters bandwidth used by them.

To use it, you install their script, or a package and run:

pagekite.py 8080 yourname.pagekite.me

And your service will be available at https://yourname.pagekite.me.

If you don’t have an account, the script will prompt you to set up an account. Pagekite takes care of monitoring the tunnel for you. They provide documentation for starting up the service at boot using rc scripts. Again, you have to start your service before you start the tunnel.

If you only want to host a set of static files:

pagekite.py /path/to/folder yourname.pagekite.me

They provide built-in defenses for so-called ‘drive-by’ attacks, by blocking requests to /wp-admin/ and similar paths by default. You can also add passwords, or restrict access by IP address (useful for the IoT camera example.)

For six hosts and 150,000 Mb of transfer, I pay 40 USD a year. They also provide a whitelabel service for IoT device makers.

Caveats

A tunnel is only as good as the endpoint. You have to trust the endpoint with your service. If it’s compromised, then you have to consider your service compromised. Google has blocklisted these services before when people acting from bad intent have used these to distribute malware. A service which requires an account might not be libre, but will have some accountablity.