How I built Ngrok Alternative
Azimjon Pulatov
Posted on July 9, 2020
Here's a quick intro of what I built
Ngrok is a fantastic tool that helps developers to expose their localhost to the Internet with minimal effort. One day I was going to share a local project with a client without deploying it somewhere. But this time I needed to expose 2 ports: one running frontend and the other backend of the project, I found out that the ngrok's free plan only allows one tunnel at a time. Later that day, I also found out that there's a 40-requests/minute limit.
Bam! An idea.
What if I build an alternative instead of paying $5/mo.?
That's what developers do, right? I also had the idea of making it open-source.
It's time to plan.
There are obviously 3 parts:
- a developer with a command-line tool (cli)
- a proxy server
- a client with a browser.
I was sure there had to be at least those steps to make it work:
- a developer connects to the server via a cli with a port number:
jprq 8000
- the server responds with an assigned domain.
amazing-coder.jprq.live
- a client opens the domain in a browser:
https://amazing-coder.jprq.live
- the server receives the request and sends it to the cli.
- the cli makes the request to localhost at the given port and sends the response to the server.
- the server responds back to the client with the response it received from the cli.
Here's a chart to help you picture those steps.
The cli and the server needs to make back and forth communication. A carefully managed TCP Sockets would do a great job but would take a long time to implement.
I decided to use and used the WebSocket Protocol. As you might know, WebSocket is a hop-by-hop protocol and sadly, my ngrok alternative now can't support Polling and HTTP streaming (because they never end or last too long).
The command-line tool is written in Python and published to PyPy. Currently implementing the command-line in javascript to publish in npm just for fun. And the server-side is in Golang. I think it was the best decision to choose golang because of its easy data sharing between goroutines and learned about leaking goroutines the hard way. I now have a good understanding of memory leaks because of this project.
Another small but impactful mistake I made during implementing the client-server communication was using JSON. I realized it only after adding a feature for handling files. With JSON one can only serialize strings. To turn file contents, bytes into a string, I needed to Base64 them. It turns out to be CPU intensive process. It's better to use BSON, I believe.
The project is open-source and waiting for your contribution. Take some time to visit the GitHub repo at github.com/azimjohn/jprq
Keep building,
Cheers.
Posted on July 9, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.