Build ngrok
KINDAreplaces $10/mosaves $120/yrback to the verdict
A tunnel to localhost on a VPS you already have: frp exposes a local port on a subdomain you own, Caddy terminates TLS, every tunnel is protected by default, and a local log shows and replays incoming requests. cloudflared does most of this for free; this is for owning the plumbing.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Every step below is a command you type or a file you edit.
Get it VS Code (code.visualstudio.com), Cursor or Zed. Open a folder for the project and use the editor's built-in terminal. open ↗
Verify
You can open a folder and run a command in its terminal - installfree
Why History for your code, and the way most hosts deploy.
Get it Install from git-scm.com or with your package manager, then run git init in the project folder once it exists. open ↗
Verify
git --version prints a version - decidefree
Why Cloudflare Tunnel is free and covers most hobby use with one command. This build is for wanting your own box.
Get it developers.cloudflare.com/cloudflare-one/connections/connect-networks open ↗
- accountabout $5 a month
Why The public end of the tunnel.
Get it Smallest Ubuntu 24.04 instance. open ↗
- accountfree on a domain you own
Why *.tunnel.yourdomain.com so each tunnel gets a name.
Get it Add an A record for *.tunnel pointing at the VPS.
- installfree
Why frps on the server, frpc on your machine.
Get it Download the release for each platform from github.com/fatedier/frp/releases. open ↗
Verify
frps --version and frpc --version print - installfree
Why Automatic HTTPS in front of the Node process. Without TLS the browser features this relies on (and your visitors' trust) do not work.
Get it On the VPS: follow the install steps at caddyserver.com/docs/install for Ubuntu. One Caddyfile with your domain and a reverse_proxy line is the whole config. open ↗
Verify
caddy version prints a version on the server
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
FRP_TOKENsecret | required | long-random | openssl rand -hex 32; the same value on server and client. |
TUNNEL_DOMAIN | required | tunnel.yourdomain.com | The wildcard base. |
BASIC_AUTH_USER | required | me | Default protection for every tunnel. |
BASIC_AUTH_HASHsecret | required | $2a$14$... | Caddy hash-password output. |
The build, in order
The server
frps bound to localhost with a token; Caddy issuing wildcard certificates.
Files
frps.tomlWildcard certificates need the DNS challenge; Caddy needs a DNS provider module or use per-name certificates on demand.
Files
Caddyfile
done when · tick each as it passesThe client
tunnel <port> <name> prints a URL and cleans up on exit.
Files
tunnel.sh
done when · tick each as it passesProtection
Inspection
Service and README
Operateproduct builder
Know when the tunnel host is down; keep it patched.
done when · tick each as it passes
That is the whole plan for ngrok. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- The global edge, OAuth-in-front with one flag, TCP and TLS tunnels: what ten dollars buys.
- the request inspector and replay
- OAuth and IP policies in front of the tunnel with one flag
- the global edge and its latency
- TCP and TLS tunnels without setup
- OAuth in front via Caddy's forward_auth
- TCP tunnels for databases
Need the files? The project pack on the verdict page hands your agent the whole brief · more dev tools.