Using Cloudflare Tunnels to Securely Expose Local Apps
#cloudflare
#security
#tunnels
#devops
Introduction
Exposing a local application to the internet can be risky if done without proper safeguards. Cloudflare Tunnels provide a secure, outbound-only path from your device to the Cloudflare edge, eliminating the need to punch holes in your firewall or expose your IP. This guide walks you through setting up a Cloudflare Tunnel to securely expose a local app, while keeping it protected with access controls and observability.
What is Cloudflare Tunnels
Cloudflare Tunnels (formerly Argo Tunnels) run a lightweight daemon called cloudflared on your machine. The daemon creates an encrypted tunnel from your local service to Cloudflare’s edge, allowing traffic to reach your app via a Cloudflare-managed hostname or DNS entry. Key benefits include:
- No inbound ports opened on your router
- TLS termination at Cloudflare
- Layered security through Cloudflare Access (Zero Trust)
- Easy DNS routing to the tunnel endpoint
Prerequisites
- A Cloudflare account and a domain managed in Cloudflare
- Access to the machine hosting the local app (developer workstation, CI runner, or server)
- Local app listening on a port (e.g., http://localhost:8080)
- Basic familiarity with the command line
Install and authenticate cloudflared
- Install cloudflared:
- macOS: brew install cloudflare/cloudflare/cloudflared
- Linux: download the binary from Cloudflare and move it to your PATH
- Windows: download the executable from Cloudflare and add it to PATH
- Authenticate with Cloudflare:
- Run: cloudflared login
- This opens a browser to select the domain you want to use and saves credentials locally
Create and configure a tunnel
- Create a named tunnel:
- cloudflared tunnel create my-app
- Note the tunnel UUID that is printed; you’ll use it in config
- Configure the tunnel to point to your local service. Create a config file at ~/.cloudflared/config.yml with content similar to:
- tunnel:
credentials-file: /path/to/credentials.json - ingress:
- host: app.example.com service: http://localhost:8080
- service: http_status:404
- tunnel:
- Route DNS for the hostname:
- cloudflared tunnel route dns my-app app.example.com This creates or updates a DNS entry (CNAME) that points to the tunnel’s edge endpoint.
Run the tunnel
- Start the tunnel:
- cloudflared tunnel run my-app
- Optional: run as a service (example systemd unit)
- Create a unit that starts cloudflared with the config file
- Enable and start the service so the tunnel restarts on boot
Secure access with Cloudflare Access (Zero Trust)
- In the Cloudflare dashboard, navigate to Access > Applications and add a new application for app.example.com
- Configure policies to require authentication from your identity provider (e.g., SSO, email verify, or groups)
- You can also set additional rules, such as restricting access by country, device posture, or MFA requirements
- Ensure that the DNS entry (app.example.com) is proxied through Cloudflare (orange cloud) so that traffic passes through Access
Best practices for reliability and security
- Use a dedicated tunnel for each local app to minimize blast radius
- Keep credentials.json secure and rotate credentials if needed
- Use short-lived authentication and enforce strong identity provider policies
- Enable logging and audit trails in Cloudflare to monitor who accessed the app
- Consider adding a health check or a simple /health endpoint and monitor tunnel availability
- If exposing multiple services, consider a subdomain strategy (e.g., app1.example.com, app2.example.com)
Troubleshooting tips
- If the app isn’t reachable, check:
- The local service is listening on the expected port (e.g., localhost:8080)
- The ingress rule matches the host you’re using
- DNS for app.example.com resolves to Cloudflare and is proxied
- cloudflared logs for errors (e.g., authentication or certificate issues)
- Verify that Cloudflare Access policies are still valid and that the user’s identity is permitted
Conclusion
Cloudflare Tunnels offer a practical and secure way to expose local apps without opening inbound ports. When paired with Cloudflare Access, you gain identity-based access control, visibility, and auditing, helping keep development and internal tools accessible to the right people without compromising security.