I enjoy using ngrok quite a bit to expose my laptop temporarily to the world for testing or demoing. However, every time I have to restart ngrok, the subdomain changes unless I pay $60/year for a better account. I’m not against paying, in fact, I support paying for software that I use, but being a tinkerer, there’s gotta be a better and cheaper way using my currently available resources.
Here are my requirements for the replacement solution:
- Free: to use an existing server.
- Easy to start: similar to ngrok, locally, I should only need to run a SSH command to connect to the remote server and start forwarding the local port. It has to be DEAD SIMPLE.
- Permanent: the public endpoint needs to be permanent. I only need to configure the DNS once and forget about it.
- SSL: The endpoint needs to serve through SSL, using Let’s Encrypt.
- Secure: I can disconnect anytime and the tunnel is dead.
I found a post from StackOverflow on setting up the SSH side of thing, and I was able to configure the whole process through and I’m quite happy with the result.
So to save you the trouble, let me walk you through the whole setup.
0. What you need to make this work:
- A server with root access (to configure nginx and certbot)
- Access to modify your DNS
- 15 minutes of your time
1. Configure DNS to Add Permanent Subdomain
You need to add a new A record to point to your server, like dev.mydomain.com. This will be the fixed subdomain that the outside world will see. In my case, I use dev.mydomain.com
2. Setup SSL with certbot
Let’s Encrypt provides a quick and easy way to implement SSL for your server. The whole process is super simple. You can read more on how to install Let’s Encrypt
certbot on Digital Ocean’s Guide.
It boils down to:
- SSH to your box.
certbot: (I’m using Ubuntu)
sudo add-apt-repository ppa:certbot/certbot
sudo apt install certbot
sudo certbot --nginx -d dev.mydomain.com
(You can choose option 2 when prompted by
certbot will show something like this:
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/dev.mydomain.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/dev.mydomain.com/privkey.pem Your cert will expire on 2019-05-29. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew"
I bolded the 2 important files that we will need to configure our Nginx.
3. Setup Nginx
We only need to add a new subdomain configuration for Nginx to start accepting traffic. I prefer to isolate all configurations for a particular domain, or subdomain into its own Nginx configuration file.
- Add a new subdomain configuration to
/etc/nginx/sites-available/dev.mydomain.com(replace mydomain.com with your domain)
- Remember to replace the correct domain and the correct path to the fullchain.pem and privkey.pem files from step 2 above.
- Symlink the new configuration file
cd /etc/nginx/sites-enable/ sudo ln -s ../sites-available/dev.mydomain.com .
- Clean up the main nginx configuration file of the stuff that certbot inserted.
sudo vi /etc/nginx/sites-available/default. You should remove all the references to the dev.mydomain.com part. Just look for the
# managed by cerbotcomment that are relevant to the
dev.mydomain.comand clean those lines up.
- Reload nginx:
sudo nginx -s reload
- You should now be able to hit https://dev.mydomain.com and you’ll see a 503 error page. This means that nginx is now serving the SSL version of the site but it’s unable to proxy to the local port 30000 that we define in the configuration. Congratulations, you’re almost there.
4. Tunnel and Profit
On your local machine, we now open the connection to the remote server.
ssh -f -N -T -R 30000:localhost:3000 remoteserver
-fto background the ssh command after authentication so you can close the command line. For testing, remove the
-Nto save resources as we’re not sending any commands.
-Tto have a non-interactive session, e.g. you are not issuing any commands. We only ssh in to create a tunnel bridge.
-Rto tell SSH to forward all traffic on the remote server that hits port 30000 to forward to our local machine on port 3000.
You can read more about this on this excellent guide on StackExchange.
You should now be able to hit https://dev.mydomain.com and start seeing the content.
This process is pretty painless and it satisfies all of the above requirements. As an extension, you can setup dev1, dev2, dev3 if you have multiple applications with different ports.