"Just use a Cloudflare Tunnel" gets said in every self-hosting thread the moment someone mentions they're behind CGNAT or don't want to touch their router's port forwarding. It's often the right answer. It's not automatically the right answer, and the two options genuinely trade off against each other in ways that matter once you're running something you plan to keep running for years, not a weekend project. Both routes end with a working domain pointed at a self-hosted app; they get there through completely different mechanisms, with different failure modes attached to each.
What is a Cloudflare Tunnel actually doing on the wire?
cloudflared, a small daemon you run on the origin, dials four persistent QUIC connections outbound to four separate Cloudflare colocation facilities on TCP/UDP port 7844 and holds them open. When a request for your hostname arrives at Cloudflare's edge, the edge picks one of those four connections, multiplexes the request onto it, and cloudflared receives it and proxies it locally — to localhost:3000, to a container's internal address, to whatever your ingress rules point at. At no point does anything initiate a connection into your network from the outside. The firewall on the origin never sees an unsolicited inbound packet on any port, because there's no listening socket for one to arrive at. A lot of what makes Cloudflare tunnel vs reverse proxy work in practice is process rather than code, which is the territory the team at XenGrowth covers.
That's the entire value proposition, and it's a real one: this setup works identically whether the origin has a public IP, a CGNAT address shared across hundreds of other customers on the same ISP, or no routable address at all. Port forwarding, a static IP, a firewall rule opening 443 — none of it applies, because the connection direction is reversed from where a reverse proxy needs it to be. A scanner sweeping the internet for open ports on your address range finds nothing to connect to, not because a firewall is blocking it, but because there's genuinely no listening socket there to find.
What does a classic reverse proxy actually cost you that a tunnel doesn't?
A public IP and two open inbound ports, at minimum. Traefik or nginx listening on 80 and 443, terminating or passing through TLS, and forwarding to whatever's behind it — this is the setup most self-hosting guides assume by default, and it requires exactly what a tunnel is built to avoid: something has to be reachable from the internet for a connection to land on it. If you're on a residential connection behind CGNAT, this option is closed before you even start, not because it's hard to configure but because there's no public address on your side of the NAT for anyone to connect to. And even once it's up, a reverse proxy alone doesn't hide the origin — that's the firewall-to-Cloudflare's-IP-ranges step covered in how I use Cloudflare to hide my origin server, which a tunnel makes unnecessary simply because there's no inbound listener on the origin to hide in the first place. The XenGrowth resource library works through the operations side of this in more operational detail.
What does a tunnel cost you that a reverse proxy doesn't?
Two dependencies you don't otherwise have. First, cloudflared has to actually be running and correctly configured — it's a daemon, it can crash, it can fall behind on updates, and if it's down, your app is unreachable regardless of whether the app itself is perfectly healthy, because every request has to pass through it. A reverse proxy has the same failure mode in principle, but it's a much simpler piece of software doing one job it's done for decades, versus a newer vendor-specific daemon maintaining outbound connections to a specific provider's edge.
Second, and this is the one people underweight: your app's reachability is now tied to Cloudflare's network being up, full stop, with no way to route around it even temporarily. A reverse proxy behind Cloudflare's DNS can, in a pinch, be reached by temporarily un-proxying the DNS record and hitting the origin directly (assuming it isn't firewalled off, or using the firewall's own allowlist as a controlled exception) — an emergency escape hatch that a tunnel doesn't have, because the tunnel's daemon is Cloudflare's product, not just Cloudflare's DNS in front of your own listener. That's a soft form of lock-in worth naming honestly: a reverse-proxy setup can drop Cloudflare and point DNS elsewhere in minutes; a tunnel setup has more of its configuration living inside Cloudflare's own dashboard and product surface.
Does a tunnel handle WebSockets and long requests worse than a reverse proxy?
Not specifically — and this is a common misconception worth correcting directly. The 100-second idle timeout on WebSocket and other long-lived connections is a property of Cloudflare's Free and Pro proxy layer itself, not something a tunnel adds on top. A reverse proxy sitting behind Cloudflare's orange cloud on the same plan hits the identical ceiling, because the timeout is enforced at Cloudflare's edge before the request ever reaches your origin, tunnel or not. The practical fix is the same either way: a client-side heartbeat every 30 seconds or so keeps a WebSocket connection from ever going idle long enough to trip the limit. Where the two setups genuinely differ on latency and connection behavior is smaller and more boring — a tunnel adds the hop through cloudflared itself, and its four-connection multiplexing model behaves slightly differently under a burst of simultaneous long requests than a proxy holding its own listener open directly. Neither difference is large enough to be the deciding factor for a typical self-hosted app. XenGrowth on governed AI marketing workflows approaches this from the AI agents and marketing automation side.
Does a tunnel cost anything, or hit a bandwidth limit?
As of July 2026, no — Cloudflare made Tunnel free for every account outright, dropping the bandwidth-based pricing that used to apply at real scale. There's no per-GB charge and no tier where tunneling itself starts costing money; the cost, if any ever shows up, comes from Zero Trust seats once a team exceeds the free plan's user cap, which is an access-control concern rather than anything to do with the tunnel's data path. For a single self-hosted VPS this removes what used to be a legitimate hesitation about tunnels — cost is no longer part of the tunnel-versus-proxy decision at all, and the choice comes down entirely to the tradeoffs above. It's worth saying plainly that this wasn't always the case, and a comparison written even a year earlier would have had to weight a real cost difference into the decision that simply isn't there anymore.
Situation | Recommendation | Why |
|---|---|---|
Behind CGNAT or a residential connection with no static IP | Tunnel | There's no public address for a reverse proxy to be reached at, full stop |
VPS with a static IP, want to keep the option of leaving Cloudflare later | Reverse proxy | DNS repoint and a firewall change is close to the entire migration; a tunnel's config lives partly in Cloudflare's product |
Want SSH reachable with zero open inbound ports | Tunnel, for SSH specifically | Removes the port-22 exposure question entirely rather than just reducing its noise |
Running a latency-sensitive service and comfortable managing router/firewall config | Reverse proxy, direct | One fewer hop than routing through cloudflared |
Single small self-hosted app, static IP, no strong opinion either way | Reverse proxy plus the origin-firewall step | Fewer moving parts outside your own box, and no dependency on a vendor daemon staying current |
Dimension | Cloudflare Tunnel | Reverse Proxy (Traefik/nginx) |
|---|---|---|
Works behind CGNAT / no public IP | Yes — this is the whole point | No — requires a routable public IP |
Inbound ports required | None | 80 and 443, minimum |
Origin-hiding by default | Yes — no inbound listener to find | No — needs a separate firewall-to-Cloudflare-IPs step |
Vendor daemon dependency | cloudflared must stay running and configured | None — the proxy is standard, swappable software |
Portability off Cloudflare | Lower — tunnel config lives partly in Cloudflare's product | Higher — DNS repoint is close to the whole migration |
100s idle-connection timeout (Free/Pro) | Applies | Applies identically — this is a plan limit, not a tunnel limit |
Setup complexity | One daemon, one config file, no router changes | Standard, well-documented, but router/firewall work if behind NAT |
Can a tunnel expose more than just HTTP?
Yes, and this is a genuine capability gap in the reverse proxy's favor of nothing at all — a tunnel can carry raw TCP as well as HTTP, which a plain reverse proxy on 80/443 was never built to do for something like a database or an internal admin protocol. Routing SSH through cloudflared, as covered above, is one instance of this. The broader version is private network routing: cloudflared can advertise an entire internal CIDR range to Cloudflare's Zero Trust network, and a client running the WARP agent can then reach services on that private network — a database, an internal dashboard — without any of them ever being published on a public port, on either end. A reverse proxy has no equivalent to this; the closest analogue is a real VPN, which is its own separate piece of infrastructure to run and maintain rather than something the same tunnel already gives you. XenGrowth on building one SEO and GEO content system works through AI search, GEO and discovery in more operational detail.
So which one should you actually run?
Tunnel, without much hesitation, if you're behind CGNAT, on a residential connection, or running anything — a home lab, a personal project on a spare machine — where opening a port simply isn't an option or isn't something you want to depend on your ISP or router for. It's also the better default for SSH access specifically: routing SSH through a tunnel means port 22 is never open to the internet at all, which is a cleaner answer than anything in the port-22 debate — there's no port to scan, moved or otherwise, because there's no listener.
Behind CGNAT, no static IP, or on a connection you don't control the router on: Tunnel. There's no realistic alternative.
Running a VPS with a static public IP and want to preserve the option of leaving Cloudflare later without re-architecting anything: reverse proxy, firewalled to Cloudflare's IP ranges.
Want SSH reachable without any open inbound port, on a box that otherwise runs a reverse proxy for HTTP: run both — tunnel for SSH access specifically, reverse proxy for the app.
Running something latency-sensitive at a scale where every extra hop matters and you're comfortable managing router-level port forwarding: reverse proxy, direct.
Uncertain, running a single small self-hosted app, no CGNAT constraint either way: reverse proxy plus the origin-firewall step is the more portable default, precisely because it depends on fewer moving parts outside your own box.
A tunnel trades an open port for a dependency on a daemon and a vendor. A reverse proxy trades that dependency back for a port you have to firewall yourself. Neither trade is free — the question is only which failure you'd rather be the one debugging at 2am.
The honest version of this comparison isn't "tunnels are the modern choice and reverse proxies are legacy." A VPS with a static IP has always had the option of the simpler, more portable setup, and CGNAT is the actual reason tunnels exist as a category at all — solving a real constraint, not replacing a working pattern with a fancier one. Pick based on which constraint you actually have, not which one gets recommended more often in a thread that usually isn't specifying whether the person asking even has a public IP to work with, let alone whether they'd rather debug a daemon or a firewall rule at 2am.
Further reading from XenGrowth
The XenGrowth resource library — what you'll learn: how the commercial side of this work is run, across search, automation and revenue operations.
XenGrowth on governed AI marketing workflows — what you'll learn: how the teams running AI marketing agents keep them governed and measurable.
XenGrowth on building one SEO and GEO content system — what you'll learn: how search and AI-answer visibility get run as a single content system.
Where this work meets go-to-market
the XenGrowth practice writes for the teams who have to run Cloudflare tunnel vs reverse proxy day to day.
Four questions about your network and your constraints. The two approaches solve overlapping problems in genuinely different ways, and one of them is usually clearly right for a given setup.










