Exposing localhost to internet using SSH tunnels

You're developing a website locally, and you need to test it on other devices for bugs, visual glitches or layout. Or you need to show your client a feature and get their feedback. Or you need to validate some configuration for a service. You need a way to access your local setup from the web. What do you do?

You've got several options. Well, for visual feedback, you might manage to satisfy your client with a screenshot. But for others, you need some interactivity, a physical connection. You can upload or commit all your progress, files and configuration every time you change something, that's cumbersome. You can also commit to a service that redirects your local traffic to web. There are some free and paid services, like localtunnel (free), ngrok (free & paid), Forward (paid with trial), but localtunnel keeps disconnecting with free server, ngrok doesn't let you have custom subdomains, and Forward is paid only.

Good thing is if you have a server with SSH access lying around, you can forego all these options. You will have a public link to your local setup with any domain you own, keep the connection open as long as you want, and any change you make is accessible to public instantly.

Configuring SSH service on server

Now we need to define some context. Say you have a domain example.com which points to a remote server at IP address r.r.r.r listening to requests on port RMT (assume 8080). On your local machine, you have an HTTP server listening to requests at local.dev (or localhost for that matter) on port LCL (assume 80).

We'll expose the local setup to internet such that any request coming to example.com:RMT will be forwarded through a secure SSH connection into local.dev:LCL on your local machine.

As a first step, you should configure SSH service for more secure practices, this includes disabling logging in as root and with a password. You can use this tutorial to set up SSH keys for Ubuntu systems as a guide. Make sure you've set up your firewall to accept connections from RMT port as well. If you haven't touched any server configuration before, fear not, DigitalOcean Community is more than enough to get you up and running.

Once this system is working fine open up a terminal and edit your SSH service configuration by

sudo nano /etc/ssh/sshd_config

add GatewayPorts clientspecified to the end, then save by CTRL + X, Y and confirm with Enter. This setting lets client specify which port SSH will listen on the public side of your server.

Setting up the connection

Now, you need start an SSH connection. This one is different from what you're used to. Open another terminal on your local machine. Type in

ssh -N -R :RMT:local.dev:LCL user@r.r.r.r
# after substituting real values
ssh -v -N -R :8080:local.dev:80 user@example.com

Explanation of switches1:

  • -R switch allocates a socket on the remote server to forward remote connections to your local machine.
  • -N disables command execution, preferable if you'll be using the connection for forwarding only.
  • -v is verbose option, useful for debugging.

This will establish an SSH connection to your remote server. If you examine the debug log, you should be able to see following messages.

debug1: Authentication succeeded (publickey).
Authenticated to r.r.r.r ([r.r.r.r]:22).
debug1: Remote connections from :8000 forwarded to local address local.dev:80

Voila! Now try going to example.com:8080, you'll be welcomed with your local website.

  1. See SSH documentation for more. ⚓︎