Self-hosted ngrok alternative

Photo by Nate Grant on Unsplash

Introduction

There are times when you need to expose your local machine to the internet during development. An example would be have an external API call your callback url to notify you about something.

In order to allow the external API to call your callback url, you need to expose your local development server to the internet but you have no access to the firewall settings.

A solution would be to use services like ngrok or serveo . These are all free services which has some limitations. In my case, the place I work at blocked ngrok and serveo is down. I needed to find another way to get out.

Here comes frp — Fast Reverse Proxy (https://github.com/fatedier/frp). It really is fast to setup and has very fast speeds.

The tools we require other than frp are the following

  1. A external server which can forward port 80, 443 and 7000 (can be others).
  2. NGINX to perform some reverse proxy
  3. A domain name to create subdomains
  4. And of course frp

Server Setup

First, we need to get the executable from the github release page. After downloading the file, extract it.

wget https://github.com/fatedier/frp/releases/download/v0.29.1/frp_0.29.1_linux_amd64.tar.gztar -xvf frp_0.29.1_linux_amd64.tar.gz 

You will see something like this in the directory

frpc  frpc_full.ini  frpc.ini  frps  frps_full.ini  frps.ini  LICENSE  systemd

For the server side, we only need 2 files. frps and frps.ini .

The config for frps.ini should look like this, assuming we want to expose a http web server.

[common]bind_port = 7000vhost_http_port = 8081token = secrettokenmax_pool_count = 100subdomain_host = frp.domain.com
[web]type = http

After updating the configuration file, we can start the server by running the command below.

./frps -c frps.ini

If successful, you will see something like this

2019/11/10 00:58:51 [I] [service.go:141] frps tcp listen on 0.0.0.0:70002019/11/10 00:58:51 [I] [service.go:183] http service listen on 0.0.0.0:80812019/11/10 00:58:51 [I] [root.go:205] start frps success

Next is to port forward 80, 443 and 7000. If you’re using a cloud solution like digitalocean, just enabling ufw and forward the ports.

NGINX

In order to hide the ports internally, we use NGINX to reverse proxy the incoming requests. We will also setup wildcard https cert using certbot so that we can have https endpoints.

I will jump straight into the configuration files as I assume you already have NGINX installed.

Firstly, create a new configuration file under /etc/nginx/sites-available

sudo mkdir /etc/nginx/sites-available/frp.domain.com.conf

Next create an absolute path to sites-enabled.

sudo ln -s /etc/nginx/sites-available/frp.domain.com/conf /etc/nginx/sites-enabled/

Now we will configure our file frp.domain.com.conf to look like the text below.

server {   server_name *.frp.domain.com;   listen 80;   location / {      proxy_pass http://127.0.0.1:8081;      proxy_set_header    Host            $host:80;      proxy_set_header    X-Real-IP       $remote_addr;      proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;      proxy_hide_header   X-Powered-By;}listen 443 ssl;ssl_certificate /etc/letsencrypt/live/frp.domain.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/frp.domain.com/privkey.pem;include /etc/letsencrypt/options-ssl-nginx.conf;ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;}server {if ($host = .frp.domain.com) {return 301 https://$host$request_uri;} 
listen 80;return 404; }

The only important thing to change here is the frp.domain.com to your own domain. The rest can be the same if you followed the same settings in frps.ini.

Now that’s done, the server side is almost complete. We just need to get our certs from certbot.

HTTPS Certs

Before we acquire the certs, let’s setup our DNS records first.

A frp.domain.com 123.123.123.123
CNAME *.frp.domain.com frp.domain.com

Installation instructions can be found here. https://certbot.eff.org/lets-encrypt/ubuntuxenial-nginx.html

I will just include the instructions here for convenience.

sudo apt-get updatesudo apt-get install software-properties-commonsudo add-apt-repository universesudo add-apt-repository ppa:certbot/certbotsudo apt-get update

Next we’ll install the package

sudo apt-get install certbot python-certbot-nginx

Once done, we can run this command to get the certs.

sudo certbot --server https://acme-v02.api.letsencrypt.org/directory -d *.frp.domain.com --manual --preferred-challenges dns-01 certonly

Do note that this requires a creation of DNS TXT record. Once completed and verified, your cert can be found in the folder /etc/letsencrypt/live/frp.domain.com .

That is all for the server configuration! Let’s move on to our local computer which we want to expose.

Client Configuration

Download the correct executable for your machine just like the server previously. This time, we will need frpc and frpc.ini .

Modify your frpc.ini to something like below.

[common]server_addr = frp.domain.comserver_port = 7000token = secrettoken[web]type = httplocal_port = 3000 # Your local web server portsubdomain = awesome

Save the file and run the command to get the client connected to the server.

./frpc -c frpc.ini

You should see this if you connected successfully to the server.

2019/11/10 01:20:10 [I] [service.go:249] [ad8e2b40a3c501d2] login to server success, get run id [ad8e2b40a3c501d2], server udp port [0]2019/11/10 01:20:10 [I] [proxy_manager.go:144] [ad8e2b40a3c501d2] proxy added: [web]2019/11/10 01:20:10 [I] [control.go:164] [ad8e2b40a3c501d2] [web] start proxy success

That’s all! Now head over to https://awesome.frp.domain.com and you will see your local web server on that domain. It works in http too.

If you want to change another subdomain, you can just modify the subdomain in frpc.ini and access it like the previous.

Conclusion

The setup may seem like a lot of steps, but most of the steps are just modifying the configurations. I have put together a working recipe for setting up a tunnel for http/https endpoint but it is not limited to http. We can also do udp tunneling whereby if we were to host a VNC Server , we can use the same method and access our “local” computer remotely.

programmer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Think before you code

Ultimate Guide to Connecting to Office 365 Outlook using Azure Logic Apps

Modern Device Management with Microsoft 365 Business Premium-Part 6

Implement Midtrans payment gateway in Flutter by using Snap method

All about Pythonic Class: The Birth and Style

Prepare to work from home

Multiplex TLS Traffic with SNI Routing

Git for Software Development

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
hc

hc

programmer

More from Medium

Introducing OpsTree Tomcat Image

How to Install Self-Managed GitLab with Nginx Reverse Proxy and Let’s Encrypt SSL in Ubuntu 20.04

Embedded System Project #6: Serial Communication

Traefik as Reverse Proxy