Zero Trust Tunnels Through Cloudflare: What Actually Happens When You Set This Up
Most people treat Cloudflare Tunnel as just another way to avoid opening ports on their router. That is not what it does. It replaces the traditional VPN model entirely for many use cases by creating an outbound-only connection from your internal service to Cloudflare's edge, then routing authenticated traffic through that tunnel without exposing any public IPs or inbound firewall rules. I spent about three weeks last year migrating a small infrastructure from a WireGuard VPN to Cloudflare Zero Trust tunnels. The migration itself took roughly six hours including testing, but the debugging phase on day two added another four because I had overlooked one specific detail about how TCP keepalives interact with the Cloudflared process. I will come back to that.
Unlocking Secure Remote Access With Zero Trust Tunnels And Cloudflare
The core mechanic is straightforward once you stop thinking about it like a traditional remote access tool. You install cloudflared on a machine inside your network. It opens an encrypted outbound connection to Cloudflare's nearest POP. You then configure routing rules in the Zero Trust dashboard that tell Cloudflare where to send incoming requests based on hostname, path, or authentication requirements. No inbound ports. No VPN client software on the user side unless you explicitly want one. Here is the practical setup sequence that actually works without hitting unexpected blockers. First, create a Cloudflare account and add your domain. Verify DNS ownership. Then install cloudflared on your target machine using the official binary or your package manager. On Linux, the commands are simple enough: download the release, place it in /usr/local/bin, and make it executable. The exact version matters less than using something newer than late 2023 because earlier builds had a memory leak under sustained load that I encountered on a different project.
Authenticate the daemon with your Cloudflare account using cloudflared tunnel login. This generates a certificate file in ~/.cloudflared/. Next, create the tunnel with cloudflared tunnel create your-tunnel-name. This gives you a tunnel UUID and a credential file. Store that credential file somewhere safe because losing it means recreating the entire tunnel and rebinding all your services. Now configure what the tunnel exposes. You edit a YAML file, typically at ~/.cloudflared/config.yml, and define your routes. A minimal example looks like this: hostname: your-service.yourdomain.com
tunnel: your-tunnel-uuid
credentials-file: /path/to/creds.json
ingress:
- hostname: your-service.yourdomain.com
service: http://localhost:8080
- service: http_status:404
Get the Full Details

The last rule is critical. Without a catch-all ingress rule, cloudflared refuses to start. I lost about twenty minutes on my first attempt staring at logs that simply said the config was invalid before realizing the missing default rule was the problem. Register the tunnel with cloudflared tunnel route dns and start it with cloudflared tunnel run. That is the basic version. The production setup uses a systemd service with automatic restarts and runs the tunnel as a dedicated user rather than root. But the real value comes from the Zero Trust side of things. Once your tunnel is running, you log into the Cloudflare dashboard and navigate to Access. You can create policies that require email verification, OTP, SSO through Okta or Google Workspace, or device posture checks before allowing anyone to reach your service. This replaces the entire concept of trusting a network location. The user identity becomes the boundary instead of the IP address.
I configured SSO integration for a team of about fifteen people. The setup took roughly forty-five minutes end to end including the OIDC client registration on the IdP side. The most time-consuming part was not the Cloudflare configuration but dealing with the identity provider's admin console, which varies dramatically depending on which one you use. Azure AD requires a completely different workflow than Google Workspace, and Okta sits somewhere in between in terms of friction. There are a few things that nobody really warns you about upfront. TCP keepalive settings on your internal service matter more than you would expect. If your backend drops idle connections after five minutes and Cloudflare expects to maintain the tunnel path, you will see intermittent connectivity issues that look completely random from the outside. The workaround is either setting keepalive at the application level or adding a simple TCP proxy in front of your service that maintains the connection. I ended up using socat with a keepalive parameter because it was the quickest solution and it worked reliably. Another issue is DNS resolution for internal hostnames. If you are routing to services that only exist on your internal network and you need Cloudflare's edge to resolve them, you have to configure internal DNS within the Zero Trust setup. This is not obvious from the documentation. The option exists under Zero Trust > Network > DNS, and you point it at your internal resolver. Without this, any ingress rule targeting an internal hostname fails silently because Cloudflare cannot resolve it.
Bandwidth is another constraint worth mentioning. The free tier gives you fifty GB of egress per month, which sounds generous until you are serving anything video-related or running a large file download service. After that, it is thirty dollars per additional terabyte. For most internal tools this is irrelevant, but if your remote access use case involves large file transfers or media streaming, the costs add up faster than people expect. The authentication options have gotten more capable recently. Device posture checks can verify that a connecting machine has full disk encryption enabled, runs a supported OS version, or has a specific endpoint protection agent installed. This is useful if you are granting access to sensitive internal systems and need some assurance about the client device. The feature works with Windows, macOS, and Linux, though the Linux implementation requires installing a small agent and the configuration is not as polished as the desktop versions. One thing that trips people up is the difference between a standard tunnel and a private network tunnel. A standard tunnel exposes your service through Cloudflare's public edge with all the usual DDoS mitigation and caching benefits. A private network tunnel creates a direct connection without routing through the public edge, which is necessary when your service communicates with other internal resources behind Cloudflare's network. The tradeoff is that you lose the CDN and WAF protections on that traffic. Choose based on whether you need the extra security layer or direct connectivity.

Monitoring is adequate but not great. The dashboard shows bandwidth usage, connection counts, and error rates at the tunnel level. Individual service metrics require you to check the cloudflared logs directly. For a small setup this is fine. For anything larger, you will want to pipe those logs somewhere with structured querying, which means setting up the JSON log format and shipping to a logging platform. This adds complexity but is necessary if you need to debug issues at 2 AM. The biggest practical advantage over a traditional VPN is the granular access control. With a VPN, you typically get all-or-nothing network access once connected. With Zero Trust tunnels, you can define exactly which service each user or group can reach, combine that with time-based restrictions, and require step-up authentication for sensitive resources. This level of control is genuinely harder to implement with a standard VPN solution without significant additional tooling. There are scenarios where this approach does not work well. If you have services that require low-latency bidirectional communication like real-time audio or interactive remote desktop, the added hops through Cloudflare's edge may introduce noticeable lag. In those cases, a traditional site-to-site VPN or direct WireGuard connection remains the better choice. The tunnel architecture prioritizes security and manageability over raw performance.
Similarly, if your internal services depend on multicast traffic or specific network-level protocols that do not work through a proxy, tunnels will not help. They handle standard TCP and UDP traffic well, but anything requiring raw network access falls outside the model. For the typical use case of securely exposing internal web applications, dashboards, and APIs to remote users, Cloudflare Zero Trust tunnels are one of the simpler and more reliable solutions available. The initial setup has a learning curve, mostly around understanding the distinction between tunnel configuration and Access policy configuration, but once those pieces click, the ongoing maintenance is minimal compared to managing VPN certificates and client software across a distributed team. If you are starting from scratch and do not have legacy VPN infrastructure to migrate, you can have a basic tunnel running in under thirty minutes. Adding full SSO and device posture checks adds another hour or so depending on your identity provider. The total time is nowhere near what you would spend configuring and maintaining a comparable VPN setup, which usually involves certificate authorities, client distribution, and ongoing key rotation procedures.
Cloudflare's documentation has improved significantly over the past year and the community is active enough that most problems have been discussed somewhere. The official docs are at cloudflare.com/zero-trust and the tunnel daemon is available through their GitHub releases page. The binary is signed and the installation instructions are accurate, which is more than I can say for a lot of similar tools in this space.
