I needed a way to expose local dev servers to the internet for webhook testing. ngrok works, but Cloudflare Tunnel is free and lets you use your own domain.

Prerequisite: Cloudflare must already be managing DNS for your domain.

Install and Login

brew install cloudflared
cloudflared tunnel login

The login command opens your browser to authenticate with Cloudflare.

Create a Tunnel

You only need one tunnel. You can route multiple subdomains through the same tunnel. I’ll use dev as the tunnel name in these examples:

cloudflared tunnel create dev

This creates the tunnel and stores credentials at ~/.cloudflared/<tunnel-id>.json.

Create DNS Routes

This creates CNAME records pointing your subdomains to the tunnel:

cloudflared tunnel route dns dev dev.yourdomain.com
cloudflared tunnel route dns dev dev-backend.yourdomain.com

To remove a route, delete the CNAME record from the Cloudflare dashboard.

Configure and Run

Create ~/.cloudflared/config.yml:

tunnel: <tunnel-id>
credentials-file: /Users/you/.cloudflared/<tunnel-id>.json

ingress:
  - hostname: dev.yourdomain.com
    service: http://localhost:5174
  - hostname: dev-backend.yourdomain.com
    service: http://localhost:4002
  - service: http_status:404

The last rule is a required catch-all for unmatched requests.

Then normally, you’d just run:

cloudflared tunnel run dev

Both subdomains now route to their respective local ports.