localhost.run: the origin story

The Past

Tom van Neerijnen
localhost.run

--

I used to have a small ec2 instance for webhook development. I’d either work directly on it or, if I wanted to use exotic toys like IDEs, I’d have an inotify locally that scp’ed changes to my ec2 instance and restarted the server. This wasn’t great, it made me sad face with just one webhook, but the moment I started working on two different webhooks simultaneously I knew it had to change. And I had just the thing to fix it.

There’s a command on every modern operating system that I realised could simplify how I used my ec2 server. SSH is what we use to log into servers, but it’s so much more. When you SSH into a server you have an outer connection, and an inner channel. It’s this channel that you see in your terminal. Those channels don’t have to be terminals tho, they can carry arbitrary TCP traffic in either direction, and you can open as many channels as you want on a single SSH connection.

ssh -R8080:127.0.0.1:8080 ec2-user@toms-ec2-instance

Now I could listen for connections on port 8080 on my ec2 instance with my webhooks configured with the instance address, and forward them thru my SSH tunnel back to port 8080 on my local machine (back then it was a desktop). This was better, but it still wasn’t quite what I wanted. I couldn’t handle multiple domain names on the same port at the same time.

Around this time I’d been looking for an excuse to try out Python 3 along with asyncio and I’d just found it. I used a most excellent library called asyncssh to write a simple SSH server, but one that could handle multiple domain names, and so version 0.0.1 of localhost.run was born.

The Present

Since then I’ve added dynamic sub domains and TLS, I’ve battled phishing websites, I’ve added functionality to handle custom domain names and certificate generation, I’ve written an admin interface for managing those custom domain names, and I’ve fixed countless bugs and logic errors, and I’ve learned so much about the amazing SSH protocol.

The future

What’s next? So much. I am sorting out the frontend (I’m not a web dev so this is slow work). Teams needs some work but a lot of the functionality for it is already in the code. And a huge one, I want to experiment with embedding the venerable mitmproxy (license willing of course) into the sessions. But it’s already a useful tool (I use it daily for my day job), so pls try it for free by running ssh -R80:127.0.0.1:8080 ssh.localhost.run to serve an app running locally on port 8080, and if you like it check out custom domains at https://admin.localhost.run/

--

--