self-hosted ngrok or serveo alternative?

August 4, 2019 2.4k views
Development

I need a way of sharing a consistent public url to my local development environment, but I don’t want to buy an ngrok or serveo subscription, and I already have a server.

Is there a self-hosted alternative to ngrok or serveo that I can install on the server and on my local machine that would allow me to tunnel:

http://subdomain.mydomain.com –> http://localhost:3000

Is there a way to handle SSL (https://subdomain.mydomain.com) as well?

1 Answer

Hello,

This can be done using Nginx, Let’s encrypt, and SSH reverse tunnelling. ngrok or serveo are really cool, but sadly they do cost a lot.

In order to configure everything please follow the listed steps:

1. Configure Nginx:

Use a server block like this, so that incoming HTTP connections to tunnel.yourdomain are reverse proxied into the application listening on port 3000.

server {
    server_name tunnel.yourdomain;

    access_log /var/log/nginx/$host;

    location / {
        proxy_pass http://localhost:3000/;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_redirect off;
    }

    error_page 502 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

With this configuration in place, suppose I visited tunnel.yourdomain. Nginx will receive the connection, and see that it should reverse proxy it. It will effectively pass the connection on to whatever application is listening on port 3333. Currently, there is nothing listening on this port, so we will get a 502 Bad Gateway or 404 Not Found error from Nginx.

2. Using an SSH reverse tunnel

SSH reverse tunnelling port N to port K means making sshd listen on port N and effectively transfer incoming connections over the SSH connection to the SSH client. The SSH client will then transfer the connection to the application listening on port K on the client machine.

Here’s the command to run on your client machine:

ssh -R N:localhost:K yourdomain

An interactive session on your server should begin; while it is open, the reverse tunnel from port N to port K is active, and sshd will allow connections originating only from localhost, i.e. your server.

Choosing N = 3000 will make it so Nginx reverse proxies incoming connections on tunnel.yourdomain into sshd, over the SSH connection, and into the application running on your local machine on port K.

To test this out, on your local machine, in one shell run:

python -m http.server 8888 

and in another shell run:

ssh -R 3000:localhost:8888 yourdomain 

Visit tunnel.yourdomain and you should see a directory listing for whatever directory you were in when you ran the Python command!

3. Securing the connection in the browser
The connection the browser is making to Nginx is at the moment not secure: it was a plain HTTP connection. You can fix this by obtaining a free SSL certificate with Let’s encrypt, and using it to secure the connection the browser is making.

The first step to using Let’s Encrypt to obtain an SSL certificate is to install the Certbot software on your server.

Certbot is in very active development, so the Certbot packages provided by Ubuntu tend to be outdated. However, the Certbot developers maintain a Ubuntu software repository with up-to-date versions, so we’ll use that repository instead.

You can follow this wonderful article on DigitalOcean website for the installation of Let’s Encrypt SSL on Ubuntu 18 using Certbot

https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-18-04

*Once you have a certificate, it suffices to adjust the Nginx server block above so it looks like this:
*

server {
    server_name tunnel.yourdomain;

    access_log /var/log/nginx/$host;

    # These three lines are new.
    listen 443 ssl;
    ssl_certificate /path/to/tls/cert/fullchain.pem;
    ssl_certificate_key /path/to/tls/cert/privkey.pem;

    location / {
        proxy_pass http://localhost:3000/;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_redirect off;
    }

    error_page 502 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

Only three lines need to be added!

Conclusion:

By combining these off-the-shelf tools, we essentially replicated the core functionality of the Ngrok and serveo. Using this double-reverse-proxy technique, web applications running on a machine behind NAT or a firewall can be accessed easily and securely from a public domain or IP address.

Let me know if you have any questions.

Alex

by Hazel Virdó
by Kathleen Juell
In this tutorial, we will show you how to use Let's Encrypt to obtain a free SSL certificate and use it with Nginx on Ubuntu 18.04. We will also show you how to automatically renew your SSL certificate. If you're running a different web server, simply follow your web server's documentation to learn how to use the certificate with your setup.
Have another answer? Share your knowledge.