Question

self-hosted ngrok or serveo alternative?

Posted August 4, 2019 16.5k 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?

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

×
4 answers

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.
  • i try it.. and i have problem “connection time out” in powershell, i see my port 22 is open.. you have solution?

    Thx.

    • Hello, @BruceWayne7

      Could you please let me know on which step you’re experiencing the “connection time out” error? Can you give me the exact command that you execute so I can try to help you with this error?

      I must say that I’m nor sure if there is something else that needs to be done when testing this from a Windows machine and using Powershell

      Regards,
      Alex

@rufio I’ve actually worked on this too. The project is called sish and has quite a few features.

@alexdo could you please tell me how does your solution solve the reconnection issues?

Using ngrok I can completely turn off the network for any amount of time, then torn it back and the same ngrok tunnel would be still working.

I know that something similar could be done with autossh, but you only use ssh in your example.

  • Hello, @annndrey

    I think this can be done using autossh as it will automatically restart the service if it’s necessary (e.g if the service stops from a time out or if it dies for some other reason)

    An example command can be:

    autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -L 5000:localhost:3306 cytopia@everythingcli.org
    
    • ServerAliveInterval ServerAliveInterval: number of seconds that the client will wait before sending a null packet to the server (to keep the connection alive).
      Default: 30

    • ServerAliveCountMax Sets the number of server alive messages which may be sent without ssh receiving any messages back from the server. If this threshold is reached while server alive messages are being sent, ssh will disconnect from the server, terminating the session.
      Default: 3

    However this needs to be tested as there might be other tweaks that are needed to make this properly working.

    Hope this helps!

    Regards,
    Alex

@rufio There is an opensource project called tool named SHREE, which provides ssh based remote tunnels, You can deploy its server implementation on your server very easily and make tunnels from its client cli. And it’s completely free.
Disclaimer: I m the author of that project.

Submit an Answer