Cloudflare Access vs Tailscale: Architecture Compared
One proxies every request through an edge checkpoint, the other builds an encrypted mesh. Compare data paths, clients, posture checks, limits, and cost.
Cloudflare Access and Tailscale get compared constantly because they answer the same question: how do people reach internal systems without a flat VPN. They answer it with opposite architectures, and almost every practical difference between them falls out of that one choice.
Cloudflare Access is a checkpoint. Every request goes to Cloudflare’s edge, gets authorized there, and is passed down a tunnel to the origin. Tailscale is a mesh. Devices establish encrypted connections to each other directly, and a central service only distributes keys and policy.
Neither is the “more Zero Trust” option. They fit different fleets.
The data path is the real difference
Tailscale’s data plane is WireGuard between peers. Its documentation is specific about what the central service does and does not do: the coordination server exchanges public keys and distributes policy, and “the private key never, ever leaves its node.” When two devices cannot reach each other directly, traffic falls back to a DERP relay, and even then “there is never a way for a DERP server to decrypt your traffic. It just blindly forwards already-encrypted traffic from one node to another.” Tailscale describes the control plane as “hub and spoke, but that doesn’t matter because it carries virtually no traffic.”
Cloudflare Access sits in the opposite position. It is a reverse proxy, and a reverse proxy terminates the connection by definition: the request is decrypted at the edge, evaluated against policy, and re-sent to the origin over the tunnel. That is what makes the clientless browser experience and per-request logging possible, and it is also the thing to be deliberate about. If your requirement is that no intermediary can process application plaintext, a proxy model is the wrong shape regardless of vendor.
The flip side is that a proxy can enforce and record things a mesh cannot see. Per-request authorization produces a decision log covering who reached which application and when.
What has to be installed
This is usually the deciding factor in practice.
| Cloudflare Access | Tailscale | |
|---|---|---|
| Browser access to an internal web app | No client needed; the hostname is public and Access authenticates at the edge | Client required on the device, or reach it through a subnet router |
| Non-HTTP protocols (SSH, RDP, databases) | Device client or protocol-aware routing | Native; it is just IP connectivity inside the tailnet |
| Contractor or unmanaged laptop | Browser plus an identity provider login is enough for web apps | Device must join the tailnet |
| Appliances that cannot run an agent | Reached through the connector on the internal network | Reached through a subnet router |
If most of what people need is a handful of internal web applications and some of those people are outside your device management, Cloudflare’s clientless path removes an entire onboarding problem. If what people need is SSH, database ports and arbitrary internal services on managed machines, Tailscale gives you that without protocol-by-protocol plumbing.
The same trade-off shows up in reverse. Cloudflare’s non-HTTP story requires the device client or protocol-aware routing, which is the part teams most often defer, leaving a legacy VPN running “just for SSH” indefinitely. That leftover path becomes the weakest link, a point covered in Zero Trust access and tunnels instead of VPN ingress.
Policy models
Cloudflare Access policies are built from three rule types with defined boolean behaviour: Include acts as OR, Require acts as AND, Exclude acts as NOT. Four actions exist: Allow, Block, Bypass and Service Auth. Bypass disables Access enforcement for matching traffic and does not log those requests, which is why the documentation warns against it for internal applications and blocks identity selectors on it.
Evaluation order is documented and worth memorising, because it is not what most people assume: “Bypass and Service Auth policies are evaluated first, from top to bottom as shown in the UI. Then, Block and Allow policies are evaluated based on their order from top to bottom.” Once a user matches an Allow or Block, evaluation stops. A later policy cannot override an earlier decision, so a permissive rule sitting above a restrictive one is not merely redundant, it is the effective policy.
Tailscale expresses policy as a tailnet policy file: groups, tags, and grants describing which sources may reach which destinations on which ports. It is a single reviewable document, which is a genuine advantage for audit, and it is bounded by plan tier. The Personal plan allows up to 3 ACL groups, Standard up to 10, and Premium up to 300. On a small tailnet that is invisible; on a large one, group count is a design constraint you hit early.
Device posture
Cloudflare’s posture checks run through its client and are documented per operating system. The coverage is uneven in ways that matter when you write a Require rule against a mixed fleet.
| Posture check | Windows | macOS | Linux | iOS | Android / ChromeOS |
|---|---|---|---|---|---|
| OS version | yes | yes | yes | yes | yes |
| Require WARP | yes | yes | yes | yes | yes |
| Require Gateway | yes | yes | yes | yes | yes |
| Disk encryption | yes | yes | yes | no | no |
| Firewall | yes | yes | no | no | no |
| Antivirus | yes | no | no | no | no |
| Domain joined | yes | no | no | no | no |
| Client certificate | yes | yes | yes | no | no |
| Device serial number | yes | yes | yes | no | no |
| Device UUID | no | no | no | yes | yes |
| File / application check | yes | yes | yes | no | no |
| SentinelOne, Carbon Black | yes | yes | yes | no | no |
Read that table before writing a policy, not after. A Require rule on disk encryption locks out every phone. A firewall check excludes Linux. An antivirus check is Windows-only. This is exactly why posture should be logged in monitor mode before it is enforced: the people it breaks first are usually the ones who did nothing wrong.
Tailscale’s device posture story is plan-gated rather than OS-gated, which is simpler to reason about but coarser. Its pricing page lists basic device posture on the free Personal plan, limited to operating system and Tailscale version information. Integrations with MDM, EDR and XDR providers start at Standard, and Premium adds device geolocation. So the posture question you can actually ask on the free tier is “is this node current”, not “is this endpoint managed and healthy”.
Scale limits and cost
Cloudflare publishes account limits that shape large deployments: 500 Access applications, 1,000 rules per application, 500 reusable policies, 50 domains per application, 1,000 cloudflared tunnels per account, 1,000 routes per account, 50 identity providers, and 50 service tokens. Zero Trust billing is seat-based: a seat is consumed by any Access authentication event, such as a login to an application or to the App Launcher, or by a user’s devices connecting through Gateway. One identity holds one seat no matter how many applications it reaches, which is worth knowing before you size a budget per application. Cloudflare offers a free tier; because seat allowances and prices change, treat the published plans page as the authority rather than any third-party figure, including this one.
Tailscale’s plan boundaries are stated directly on its pricing page. Personal is free, with unlimited user devices, up to 6 users, up to 3 ACL groups, up to 50 tagged resources to start, and 1,000 minutes per month for ephemeral resources. Standard is $8 per user per month and adds unlimited users, SCIM provisioning, up to 10 ACL groups and the posture integrations. Premium is $18 per user per month and adds up to 300 ACL groups, just-in-time access, network flow logs and log streaming.
The shapes differ. Tailscale prices per user with generous device counts, so a small team with many machines does well. Cloudflare prices per seat with high per-account object limits, so a larger organisation publishing many applications to a mixed audience does well.
Which one fits
Cloudflare Access fits when the workload is mostly internal web applications, when a meaningful share of users are contractors or on unmanaged devices, when a per-request authorization log is a requirement, or when the same platform is already handling DNS and WAF for those hostnames.
Tailscale fits when the workload is arbitrary protocols between managed machines, when you want the least possible intermediary in the data path, when engineers need direct SSH and database access, or when a single reviewable policy file beats a dashboard.
Both together is a real answer and not a cop-out. Publishing customer-facing and contractor-facing web apps through Access while engineers run a tailnet for infrastructure access is a coherent split, because each tool is doing the job its architecture suits.
Whichever way you go, the origin’s inbound ports should end up closed either way. If Cloudflare is the direction, the tunnel setup walkthrough covers getting the first connector running, and the error 1033 guide covers what to check when a tunnel stops answering.
Sources
Related
Cloudflare WARP vs VPN: What the Client Actually Does
WARP is a tunnel, not an exit-IP service and not a LAN bridge. The MASQUE and WireGuard data paths, ports, split-tunnel defaults, client modes
Zero Trust Access and Tunnels Instead of VPN Ingress
How outbound-only tunnels, identity-aware policies, and device posture replace flat VPN network access, and the four mistakes that quietly undo it.
Cloudflare Tunnel vs Port Forwarding: Which to Use
Compare Cloudflare Tunnel and port forwarding for homelab access: CGNAT, authentication, protocol limits, privacy, VLAN isolation, firewall rules