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
- A external server which can forward port 80, 443 and 7000 (can be others).
- NGINX to perform some reverse proxy
- A domain name to create subdomains
- 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 touch /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/conf
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.