Poor Man's ngrok

May 4, 2017 by Noah

Recently, I was developing a Python/Flask app to implement Web Hooks for a third-party API that I was working with. The API recommended the use of ngrok during local development so that the server running on your local computer could be accessed publicly over the Internet (so that their API could reach yours).

ngrok is cool and all, but for their free plan they randomize the subdomain they give you every time you start the program. This meant I always had to log into my API account and change my Web Hook URL each day.

What ngrok is doing is nothing new: I've written about using SSH to forward ports between machines, and figured it should be easy enough for me to configure a subdomain on my own server that forwards traffic to another port that I could open when I need to.

I run the NGINX web server, so I just added some configuration for a subdomain that forwards all traffic to the local port 5000 on the web server:

server {
    listen [::]:443 ssl;
    listen 443 ssl;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;

    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_dhparam /etc/ssl/dhparam.pem;

    # So the Let's Encrypt Acme client can use the webroot method
    location /.well-known {
        alias /var/www/html/.well-known;

    location / {

server {
    listen [::]:80;
    listen 80;

    location / {

This makes my forward to localhost:5000 on the web server. When this port isn't currently bound to a remote SSH connection, nginx will return "502 Bad Gateway"

All that's missing now is a convenient client-side command to start/stop the tunnel when I want. For that, I added a function to my .bashrc:

# Poor Man's ngrok
tunup() {
	echo "Forwarding to local port $port"
	ssh -R 5000:$port kirsle

So I can just run tunup to open the tunnel and close the SSH session when done. (I know there's a way to start SSH in the background/without an interactive shell, but I prefer to keep a shell open so I know when it gets disconnected). If I'm using a local port on my computer other than 5000, I can run e.g. tunup 8080 for the local port number.



There are 0 comments on this page. Add yours.

Add a Comment

Used for your Gravatar and optional thread subscription. Privacy policy.
You may format your message using GitHub Flavored Markdown syntax.