This Gist explains how to establish a tunnel between a server with a public IPv4 and a server that runs an HTTPS service behind a NAT so as to make the HTTPS service available through the tunnel on the public IPv4 while completely keeping the certificate challenge and the TLS termination on the server behind the NAT. This is different from e.g. Cloudflare Tunnels which forcibly terminates the TLS connection on their own server with a public IPv4.
- Server with a public IPv4:
- Download
frps
from https://github.com/fatedier/frp/
- Download
- Server behind a NAT:
- Download
frpc
from https://github.com/fatedier/frp/ apt install caddy
- Download
- Create an
A
DNS record that points to the public IPv4 of the server where frps runs.- In my case I added an
A
record ontestcert.your.domain
pointing to123.123.123.123
- In my case I added an
- Copy
frps.toml
to the server with the public IPv4 and runfrps -c frps.toml
. - Copy
frpc.toml
to the server behind the tunnel and runfrpc -c frpc.toml
.- It should successfully connect to the frps server.
- On the server behind the tunnel, run
caddy run
:- Caddy should start, obtain the LetsEncrypt challenge, validate it, and download the certificate returned by LetsEncrypt.
- From any machine, run
curl https://testcert.your.domain/caddy.html
(replace the domain name with yours) and confirm that it works.
- To keep the example simple (and because I trust the server on which
frps
runs) I use the easyTLS-ALPN-01
challenge type rather thanDNS-01
which would run client-side behind the NAT and make it secure even if thefrps
server is pwned. - If you can't/don't want to entirely trust the server running
frps
, then you can instead use theDNS-01
challenge type and run it client-side behind the NAT. You should then blacklist the HTTP/HTTPS-based challenge methods (to only keep DNS challenges) by adding a specific TXT record in your DNS (look it up on the internet) and enable HSTS preload. Your now safe even if thefrps
server is pwned.