Cloudflare Tunnel Guide
Cloudflare Tunnel lets an app running on your laptop, VPS, or private network receive traffic without opening inbound ports or exposing its public IP. The cloudflared connector creates outbound, encrypted connections to Cloudflare; Cloudflare then forwards matching requests to your local service.
Choose the right option: use a Quick Tunnel for a short-lived demo or webhook test. Use a named tunnel with your own domain for staging and production.
Before you start
You need:
- A local web app, for example
http://localhost:3000. cloudflaredinstalled on the computer/server that can reach that app.- For a custom domain: a Cloudflare account and a domain whose DNS is managed by Cloudflare.
Download the correct cloudflared package for Linux, macOS, or Windows from the official installation page. Verify it afterwards:
cloudflared --versionFor macOS with Homebrew, this is commonly enough:
brew install cloudflared1. Fastest option: Quick Tunnel
Start your app first. For example, a Vite or React development server may run on port 5173:
npm run devIn a second terminal, expose that port:
cloudflared tunnel --url http://localhost:5173The terminal prints a temporary URL like:
https://random-words.trycloudflare.comOpen or share that URL. Requests travel through Cloudflare to your local app.
Great uses for Quick Tunnel
- Testing GitHub, Stripe, Razorpay, or other webhooks on localhost.
- Showing a work-in-progress site to a teammate or client.
- Testing a mobile device against a locally running API.
Important limitations
- The
trycloudflare.comURL is random and changes when the process stops. - It is meant for development and testing, not production.
- It will not start if
~/.cloudflared/config.yml(orconfig.yaml) already exists. Temporarily move that file or use a named tunnel instead.
2. Production option: named tunnel from the dashboard
This is the simplest production setup because Cloudflare stores the tunnel configuration and gives you a token to run on each connector.
- Sign in to the Cloudflare dashboard.
- Open Networking → Tunnels and choose Create a tunnel.
- Name it clearly, for example
portfolio-vpsorapi-production. - Select the server operating system and copy the displayed installation/run command.
- Run that command on the server. The tunnel should become Healthy in the dashboard.
- Open the tunnel’s Routes tab → Add route → Published application.
- Enter a hostname such as
app.example.comand set Service URL to your local service, for examplehttp://localhost:3000. - Save the route and visit
https://app.example.com.
Cloudflare creates the required proxied DNS route. No inbound 80, 443, or application port needs to be opened on your origin server.
A published application is public by default. If it is an admin panel, preview site, database UI, or internal API, protect it with Cloudflare Access.
3. CLI-managed named tunnel
Choose this approach when you prefer configuration in files and version control (never commit credentials). First authenticate in a browser:
cloudflared tunnel loginCreate a named tunnel:
cloudflared tunnel create my-appcloudflared tunnel listThe command creates a tunnel UUID and a credentials JSON file. Create ~/.cloudflared/config.yml and replace the placeholders below:
tunnel: YOUR-TUNNEL-UUIDcredentials-file: /Users/YOUR_USER/.cloudflared/YOUR-TUNNEL-UUID.json
ingress: - hostname: app.example.com service: http://localhost:3000 - hostname: api.example.com service: http://localhost:8080 - service: http_status:404The final catch-all rule is intentional: requests that do not match a hostname receive a 404 instead of reaching an unintended service.
Create the DNS records that point the hostnames to the tunnel:
cloudflared tunnel route dns my-app app.example.comcloudflared tunnel route dns my-app api.example.comValidate the configuration, then run it:
cloudflared tunnel ingress validatecloudflared tunnel run my-app4. Keep it running after a reboot
For a Linux production server, run cloudflared as a system service. Provide the complete config path when the configuration belongs to a non-root user:
sudo cloudflared --config /home/ubuntu/.cloudflared/config.yml service installsudo systemctl enable --now cloudflaredsystemctl status cloudflaredUseful service commands:
sudo systemctl restart cloudflaredsudo journalctl -u cloudflared -fFor a dashboard-managed tunnel, use the token command shown by the dashboard. Treat the token like a password: do not put it in screenshots, Git repositories, or frontend code.
Security checklist
- Keep the origin application bound to
localhostor a private interface when possible. - Do not open your app’s port in the cloud firewall just because a tunnel exists;
cloudflaredonly needs outbound connectivity. - Restrict access with Cloudflare Access before exposing dashboards, previews, SSH, or internal tools.
- Store tunnel credentials outside the repository and add
.cloudflared/and*.jsoncredential files to.gitignore. - Use separate tunnels/tokens for development, staging, and production.
- Keep
cloudflaredupdated and revoke/rotate a token immediately if it is exposed. - For high availability, run the same tunnel on two or more independent connectors.
Common problems and fixes
| Problem | Likely cause | What to check |
|---|---|---|
502 Bad Gateway | Cloudflare can reach the tunnel, but the connector cannot reach the local app. | Confirm the service with curl http://localhost:3000; verify the protocol and port in the route. |
| Tunnel shows Inactive or Down | cloudflared is not running, its token is invalid, or outbound traffic is blocked. | Check systemctl status cloudflared and logs. Ensure outbound port 7844 is allowed. |
404 from the tunnel | No ingress rule matched the request. | Check the hostname and ensure the catch-all http_status:404 rule is last. |
| Website redirects in a loop | Origin HTTPS redirects or Cloudflare SSL settings do not match. | Start with http://localhost:PORT as the service URL; only use HTTPS upstream when the origin certificate is valid. |
| Quick Tunnel does not start | A local config.yml/config.yaml is present. | Move it temporarily or use a named tunnel. |
| Custom hostname does not work | The zone is not active in Cloudflare or DNS is wrong. | Confirm Cloudflare is authoritative for the domain and run cloudflared tunnel route dns ... again. |
Useful commands
# Test the app locally before blaming the tunnelcurl -I http://localhost:3000
# See named tunnelscloudflared tunnel list
# Inspect one tunnel and its active connectionscloudflared tunnel info my-app
# Test how ingress rules will route a URLcloudflared tunnel ingress rule https://app.example.com
# Watch the Linux service logssudo journalctl -u cloudflared -fHelpful tools
-
Cloudflare Zero Trust dashboard: create and monitor tunnels, routes, and Access rules.
-
cloudflaredCLI: install, authenticate, create tunnels, validate ingress, and inspect status. -
Cloudflare Access: require email OTP, Google/GitHub login, SSO, or service tokens before a user reaches an app.
-
Cloudflare WARP: connect users to private network routes through Cloudflare Zero Trust rather than exposing them publicly.
-
Docker: run the connector in a container when your application is containerized:
Terminal window docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token YOUR_TUNNEL_TOKEN