Use your VPS as Ngrok Alternative (with SSH)

ngrok is a very handy tool for exposing local applications to the internet. I've been using it for a very long time.It does a good job, but the free version comes with limitations. There's a lack of freedom and you cannot even specify a fixed domain. Every time Ngrok is restarted,  you get a new domain. This is a problem if you are working on a project that heavily relies on incoming web hooks.

By the end of this article, we will write a small application, that will let you access your local application from your own domain.

Things you need:

  1. A domain name, and the ability to change it's DNS records.
  2. A VPS server (You can get one from Digital Ocean)
  3. SSH Access to the VPS server. key based authentication is preferred.
  4. SSH CLI Client installed in your local computer.
  5. Patience and ability to follow instructions.
Please do it at your own risk, avoid production servers. Some of the commands might be harmful.
Many of the commands will require Linux or mac as local computer. If you want to do it on windows, please use Linux Subsystem on Windows.

Start by Pointing your (sub)domain to the server IP address:

Open up the DNS editor and add a new A record. For the sake of this tutorial, let's assume, your domain name is yourdomain.com and the A record is : livedemo. Enter the server's public IP address as the record value. leave the TTL field to default. At this point, the url: livedemo.yourdomain.com should point to your server's IP address.

Configuring the VPS server

You have to enable GatewayPorts in your server's SSH configuration. In order to do so, SSH into the server and open the file /etc/ssh/sshd_conf and add the following lines at the end of it.

# Add GatewayPorts support
GatewayPorts yes

and then restart SSH server by running the following command for the changes to take effect:

service ssh restart

Let's create our very first Tunnel manually:

We will use a SSH feature called remote port forwarding. If you have a local application running in port 3000  and you want to access it from port 7070 in the remote server, you can write a command like this in the local computer to create a tunnel(assuming root is your SSH user):

ssh -R 7070:localhost:3000 -N root@your-server-ip

Let's look at the anatomy of the command:

ssh -R <server-port>:localhost:<local-port> -N <server-username>@<server-ip>
    

the -R flag determines that It's a Remote port forwarding, And the -N flag prevents the SSH command from landing into the remote server's shell.

As long as you don't terminate the process, you will be able to access your local application with the url (we created previously) on port 7070 using this URL: livedemo.yourdomain.com:7070

Let's turn it into a small and reusable command:

This command isn't that long, but it's still inconvenient compared to Ngrok. Let's fix that. We will call our tiny program batman, Let's create a file in /usr/local/bin named batman in the local computer, and give it execution permission by running chmod +x /usr/local/bin/batman and add the following content :

#!/bin/sh
echo "Sharing port $1 press Ctrl+C to exit"
ssh -R 7070:localhost:"$1" -N root@your-server-ip

Save the file. Now you have a small and reusable command. You can share application running on any port, with the following command from the local computer. For example, if you want to share application running on port 3000, Just enter the following command:

batman 3000

You should see an output like this:

Now if you navigate to livedemo.yourdomain.com:7070 you should be able to access the application.

Getting rid of the port number and using SSL:

You can use port 80 if if isn't already used instead of 7070. But if you have that luxury, probably you would buy Ngrok premium instead if going for this method. Let's use our old friend Nginx Instead to help us regarding this. We will create a reverse proxy to forward traffic from port 80 on domain livedemo.yourdomain.com to port 7070.

Install nginx in the server (if not already installed), and write a new configuration in the folder etc/nginx/sites-available named livedemo.yourdomain.com, with the following content:

server{
   server_name livedemo.yourdomain.com;
   listen 80;
   location /{
	proxy_pass http://localhost:7070;
	proxy_set_header Host $host;
	proxy_set_header X-Real-Ip $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	error_page 502 /500.html;
   }
   location /500.html{
	return 500 "<center>Nothing to show...</center>";
   }
}

Don't forget to make a symlink and restart the server:

# Create Symlink
ln -s /etc/nginx/sites-available/livedemo.yourdomain.com /etc/nginx/sites-enabled/

# Restart Nginx
service nginx restart

Now if you navigate to livedemo.yourdomain.com  and batman is running in your local computer, you should be able to access your application. No port required.

If you want to add SSL support, you can use free SSL from Let's Encrypt. I will not go into details in this post, They have excellent documentation.

There you have it! your very own Ngrok alternative on your very own domain. If you like the post feel free to share. Add comment if you find any mistake or have any queries.