A digital lock glowing in neon blue, a symbol of zero trust access to one application at a time.

Zero Trust vs VPN for Small Teams: Cloudflare Tunnel or Tailscale?

2026-02-23•root

Introduction

For a small project, zero trust comes down to two changes. Nothing you run for yourself answers on an open port, and nobody is let onto a network: each person, script or device gets into one application after proving who it is. A classic VPN works the other way round. It checks you once at the gateway and then gives you a route into a whole network, usually through a gateway that has to listen on the internet for anyone who knocks.

For an indie developer, a small business or a team of five, two products cover most of this without any infrastructure of your own. Cloudflare Tunnel with Cloudflare Access puts web applications behind Cloudflare's network and a login, with no inbound port on the server and nothing to install for the people using them. Tailscale builds an encrypted WireGuard network between your own laptops and servers, which suits SSH, databases and anything else that is not a web page.

The short answer to "Cloudflare Tunnel vs Tailscale": browser apps that other people open go behind the tunnel, and machine access for you and your team goes over Tailscale. The two combine well, and a small team can run both without overlap. Each still leaves gaps, and a few common mistakes turn either one back into an ordinary perimeter.


What Is Zero Trust? The One-Paragraph Version

Zero trust means nothing is trusted because of where it connects from: every request to an application has to show who is asking. It is an access model, which vendors then package into products. In practice, the check covers the identity of the person or service, sometimes the state of their device, and a policy written for that one resource. Passing the check for one application grants nothing for the next. NIST SP 800-207 (August 2020) describes zero trust as a set of ideas that "move defenses from static, network-based perimeters to focus on users, assets, and resources", and states that no implicit trust is granted to a user or device based solely on where it sits on the network. Google described running its own company this way in 2014, under the name BeyondCorp. Zero trust network access (ZTNA) is the product category that applies the idea to applications: a broker sits between the user and the app, verifies identity, and only then connects the two, so the app never has to face the open internet.


Zero Trust vs VPN: What Changes in Practice

Take a typical small setup: one VPS with a public web app, a Grafana dashboard, a Postgres database and SSH, plus a server at home. A contractor needs to look at Grafana for two weeks.

A VPN Hands Out a Network, Zero Trust Hands Out an Application

With a classic remote-access VPN, the contractor gets a VPN account. Once connected, their laptop has a route into the private subnet, and Grafana, Postgres and SSH are all reachable at the network level. The password on each service is the only thing left in the way. Firewall rules on the gateway can narrow this down, but each one is another rule to write and maintain, and without them the route covers the whole subnet. If the contractor's laptop is compromised, the attacker inherits the same route. This is the lateral movement problem: the first foothold opens the way to everything next to it.

With zero trust access, the contractor gets a login to one hostname. Grafana opens after they authenticate. Postgres and SSH do not exist from their side, because there is no route to them at all. When the two weeks are over, removing one email address from one policy ends the access.

The VPN Gateway Is Itself on the Internet

A VPN server has to accept connections from anywhere, because it cannot know in advance where its users will connect from. Its login is reachable by every scanner on the internet, and a flaw in it hands over the network behind it. In January 2024 CISA issued Emergency Directive 24-01 after observing "widespread and active exploitation" of two flaws in Ivanti Connect Secure, a widely deployed VPN appliance. One of them, CVE-2023-46805, was an authentication bypass in the very component meant to keep attackers out, and a supplemental direction later ordered federal civilian agencies to disconnect the appliances entirely.

Not every VPN has this shape. WireGuard, the protocol under Tailscale and under many self-hosted setups, does not answer at all to packets from keys it does not know. Its protocol description calls the server "silent and invisible" to an unauthorized client.

An IP Address Is Not an Identity

Older setups often end with an allowlist: the database accepts connections from the office address or from the VPN's exit address. An IP address tells you which network a packet came from, not who sent it. Addresses are shared, reassigned and rented out, and each one carries the history of everyone who used it before. Zero trust policies key on a signed-in identity instead, and use the address, if at all, as one extra condition.

Where "Zero Trust vs VPN" Stops Being the Right Question

Tailscale is technically a VPN: it builds WireGuard tunnels and gives every device a private address. What puts it in the zero trust camp is the policy layer. Identities come from your identity provider, and each connection between two devices is allowed or dropped by rules you write. Without those rules it is a flat private network, the old model with better cryptography. So the choice that matters for a small team is between network access granted once and access to one application checked on every connection, whatever the product is called.


Open Ports: Why Outbound-Only Connections Matter

Anything listening on a public address gets found. Censys documents that it continually scans the whole IPv4 space on more than a hundred common ports and walks through all 65,535 ports over time. Shodan says it crawls the entire internet at least once a week. Those are the search engines that publish their results; botnets run the same sweeps and publish nothing. A non-standard port number or a server with no DNS name does not help against a sweep that tries every address.

Both tools in this article remove the listener altogether. With Cloudflare Tunnel, a daemon on your server opens outbound connections to Cloudflare and receives requests through them. With Tailscale, devices reach each other through NAT, and Tailscale's own documentation says that most of the time no firewall port needs to be opened. Both also work behind carrier-grade NAT (CGNAT), where a home connection has no public address to forward a port to: the tunnel only dials out, and Tailscale connects through the NAT or falls back to a relay. In both cases the server's firewall can drop all unsolicited inbound traffic. Cloudflare describes exactly that as a "positive security model": block all ingress and allow only egress from the tunnel daemon. A scanner that reaches the address finds nothing to talk to.


How Cloudflare Tunnel and Cloudflare Access Work

Cloudflare Tunnel, called Argo Tunnel until 2021, starts with a small daemon, cloudflared, on the server or on any machine that can reach the service. It keeps four outbound-only connections open to Cloudflare across at least two data centers (QUIC by default, HTTP/2 where UDP is blocked), and a replica of the tunnel on a second machine adds four more. You then publish a hostname such as a Grafana subdomain. Its DNS record points at the tunnel rather than at your server, and Cloudflare's edge forwards requests for that hostname down the open connections to the local service.

On its own the tunnel only moves traffic and does not check who is asking. That is the job of Cloudflare Access, which sits in front of the hostname at Cloudflare's edge. Both products belong to Cloudflare One, the platform sold under the Cloudflare Zero Trust plans. Before a request reaches the tunnel, Access sends the visitor to a login: a corporate identity provider such as Microsoft Entra ID or Okta, a social one such as GitHub or Google, any OIDC or SAML provider, or a one-time PIN sent to an approved email address. A policy then decides who gets in: specific emails, an email domain, or members of a GitHub organization or another identity-provider group, optionally with conditions such as country or device posture. Scripts and CI jobs authenticate with service tokens instead of a person's login. Requests without a valid login are stopped at the edge and never reach your server.

When access is granted, Cloudflare attaches a signed token to the request it forwards: a JWT in the Cf-Access-Jwt-Assertion header and the CF_Authorization cookie. Cloudflare's documentation says the application should validate that token, so it can tell a request that came through Access from one that did not. It recommends checking the header, because the cookie is not always passed.

Using a published web app needs nothing but a browser, which is why this route suits contractors, clients and testers. The price is that Cloudflare terminates TLS. Its documentation describes two certificates per request, an edge certificate between the visitor and Cloudflare and an origin certificate between Cloudflare and your server, and between the two Cloudflare handles the request decrypted. That is how it can apply the login, the WAF and caching, and it also means Cloudflare can see the content of every request.

Non-web services can go through the same tunnel in three ways: an SSH, VNC or RDP session rendered in the browser after an Access login; cloudflared running on the user's machine; or the Cloudflare One Client (formerly the WARP client), which routes whole private IP ranges into the tunnel.

Cloudflare Mesh vs Tailscale

Since April 2026 Cloudflare also offers Cloudflare Mesh, the renamed WARP Connector, which gives enrolled servers and devices private addresses so they can reach each other by IP. The difference from Tailscale is the path: Mesh traffic always passes through a Cloudflare data center, while Tailscale connects devices directly whenever it can.

Media Servers and Cloudflare's CDN Terms

A published hostname is served through Cloudflare's proxy, so Cloudflare's CDN terms apply to it. On Free, Pro and Business plans they reserve the right to limit accounts that serve video, or a disproportionate share of pictures, audio or other large files, without the paid products built for that. If the service behind the tunnel is a media server such as Jellyfin or Plex, read that clause first.


How Tailscale Works

Tailscale installs a client on every device that should be part of the network (laptops, servers, phones) and builds WireGuard tunnels between them. The resulting network is called a tailnet. A central coordination server does the bookkeeping. Each device signs in through an identity provider (Google, Microsoft, GitHub, Apple, Okta, OneLogin, a custom OIDC provider, or a passkey), registers its public key, and receives the keys and the access rules for the devices it may talk to. Private keys never leave the device, and Tailscale stores no passwords: in its own words, "there are no Tailscale passwords."

Traffic does not pass through the coordination server. Devices first try to connect directly, using NAT traversal. When a direct path is impossible, traffic goes through Tailscale's DERP relay servers or through another device in your own tailnet acting as a peer relay. All three paths are end-to-end encrypted with WireGuard, and the relay forwards packets it cannot read. This is the main architectural difference from Cloudflare: Tailscale's servers handle keys, policy and relayed ciphertext, never the plaintext.

Access is controlled by the tailnet policy file, written as ACLs or grants; Tailscale recommends grants for most cases. Rules are deny-by-default and enforced on each device, but a new tailnet ships with a default policy that lets every device reach every other device, so until you write rules, Tailscale is a flat network. Three things are worth doing on the first day:

  • Replace the default allow-all policy with grants that give each group only the devices and ports it needs.
  • Tag the servers, so each has an identity of its own instead of the identity of whoever set it up. Tagged devices have key expiry turned off, while user devices must sign in again when their keys expire, every 180 days by default.
  • Turn on device approval, available on every plan, so an admin confirms each new device before it joins.

A few features do most of the work for small teams:

  • MagicDNS gives every device a name, so nobody has to remember addresses.
  • A subnet router exposes a whole LAN to the tailnet, including printers and other devices that cannot run the client.
  • An exit node sends a device's internet traffic out through another device in the tailnet.
  • Tailscale SSH replaces SSH keys with tailnet identity and can demand a fresh login before a session (check mode).
  • Serve shares a local web service with the rest of the tailnet. Funnel, still in beta, publishes it to the open internet through Tailscale's relays. It listens only on ports 443, 8443 or 10000, terminates TLS on your own device, and has a bandwidth limit you cannot configure. For a public site, Tailscale Funnel vs Cloudflare Tunnel is not a close call: the tunnel was built for that job.

If the coordination server goes down, existing connections keep working and the rules keep being enforced, because both are cached on the devices. What stops is everything that needs the center: adding devices, refreshing keys, changing rules and revoking users.


Cloudflare Tunnel vs Tailscale, Side by Side

QuestionCloudflare Tunnel + AccessTailscale
What it connectsPublic hostnames on Cloudflare's network to services behind the tunnelYour devices to each other, in a private network
What users installNothing for web apps, a browser is enoughThe Tailscale client on every device
Inbound ports on the serverNoneNone in most networks
Who can read the trafficCloudflare, which terminates TLS at its edgeOnly the two devices; relays forward ciphertext
Where policy livesPer application, enforced at Cloudflare's edgeTailnet policy file, enforced on each device; allow-all until you change it
Non-web protocolsBrowser-rendered SSH, VNC and RDP, client-side cloudflared, or the Cloudflare One ClientAnything that runs over IP
Public websitesThe main use case, with Cloudflare's WAF and DDoS protection in frontFunnel (beta): three ports, bandwidth-limited
When the vendor has an outageNew logins can fail while it lastsExisting connections continue; no changes until it is back

Cloudflare's Zero Trust free plan covers up to 50 users. Tailscale's free Personal plan allows up to six users but is for non-commercial use only, so a team working on a paid product needs one of its paid plans. Limits change, so check both plan pages before you commit.


Which One to Choose

When Cloudflare Tunnel With Access Fits

Pick the tunnel when the people who need the app should not have to install anything (contractors, clients, a QA tester) and the service is a web app such as a dashboard, a staging site or an admin panel. It is also the right tool for the public site itself, if you want the origin to have no open ports and Cloudflare's DDoS protection in front of it.

When Tailscale Fits

Pick Tailscale when the access is for you and your team from devices you control, or when the protocol is not HTTP: SSH, Postgres, Redis, RDP, a NAS, a home lab. It also fits when you do not want a third party to decrypt the traffic, and when servers at different providers or CI runners need to reach each other privately.

When to Run Both

In a small team the two divide the work cleanly. The public web app goes out through the tunnel, and admin hostnames such as Grafana or the CMS back office sit behind Access. SSH and the database are reachable only over Tailscale, and port 22 is closed to the world.

When a Plain VPN Is Still Fine

For one person and one server, a self-hosted WireGuard endpoint is small, silent to scanners and depends on no vendor. It lacks per-application policy and a central identity, and both start to matter the day a second person needs access.


Mistakes That Turn Zero Trust Back Into a Perimeter

The origin is still reachable directly. The tunnel works, Access works, and the server still answers on ports 80 and 443 at its public address, because the firewall was never closed or an old DNS record still points there. Anyone who finds the address skips the login entirely. Old hostnames turn up easily, because Certificate Transparency logs list every name a certificate was issued for, and the Subdomain Finder reads them. Close inbound ports, make the application validate the Access token, or do both. If the server was ever published under its real address, assume the address is known.

The default Tailscale ACL was never replaced. Under that allow-all policy, the contractor's laptop can reach the production database as easily as the Grafana box. Grants that give each group access only to the tags and ports it needs are what make a tailnet zero trust.

The policy is wider than it looks. In Access, an "emails ending in" rule for a public mail provider's domain admits anyone with a free account there. Cloudflare's documentation warns that using one-time PIN as an Include rule without restricting email domains "allows anyone with any email address to receive a code and access the application." Bypass policies switch Access off for matching traffic, and Cloudflare notes that such requests are not logged.

One account holds every key. Whoever controls your Cloudflare account, your tailnet admin console or the identity provider behind them controls access to everything. Those accounts deserve the strongest protection you have: passkeys or hardware security keys rather than SMS codes.

There is no way in when the vendor is down. On 12 June 2025 a failure in the storage behind Cloudflare's Workers KV made Access fail every identity-based login for about two and a half hours, while service tokens and bypass policies kept working. Keep a break-glass path that does not depend on the same vendor, such as the hosting provider's web console or a firewall rule in its control panel that you can open for your current address when you need it.


How to Check What Your Server Still Exposes

After the move, test from outside, never from the server itself. The Port Scan tool on packet.guru makes a plain TCP connection from packet.guru's server to up to ten ports you name and reports each one as OPEN, closed or filtered/timeout. OPEN means something accepted the connection. Closed means the host answered with a refusal. Filtered/timeout means nothing answered within a few seconds, which is what a firewall that drops inbound traffic looks like, and it is the result you want to see once everything sits behind a tunnel or a tailnet (closed is fine too).

Scan the server's own IPv4 address, not its hostname: a hostname proxied by Cloudflare resolves to Cloudflare's edge, so scanning it tests Cloudflare instead of your server. If the server also has an IPv6 address, check that its firewall rules cover IPv6 as well. The tool checks TCP only, so it cannot see WireGuard or Tailscale on UDP, which stay silent to strangers anyway. A sensible list for a typical VPS is 22 for SSH, 80 and 443 for the web server, 3000 and 8080 for development servers, 5432 and 3306 for databases, and 6379 for Redis. Any of them showing OPEN after the move means the origin is still on the internet, where anyone who finds it can walk around the login.


FAQ

Q: What is zero trust network access (ZTNA)?

A: A way of granting access to individual applications instead of to a network. A broker checks identity, and optionally the state of the device, then connects the user to that one application, which never listens on the open internet. Cloudflare Access is a ZTNA product. Tailscale gets a similar result with per-device rules on a private network.

Q: Is Tailscale a VPN or zero trust?

A: Both. Technically it is a mesh VPN built on WireGuard. It behaves as zero trust once you replace the default allow-all policy with rules that give each user or tag access to specific devices and ports.

Q: Cloudflare Tunnel vs Tailscale: which is more secure?

A: They protect different things. Cloudflare Tunnel with Access keeps the origin off the internet and puts a login and DDoS protection in front of it, but Cloudflare decrypts the traffic. Tailscale keeps traffic encrypted end to end between your devices, but every user needs the client and the policy is yours to get right.

Q: Is Cloudflare Tunnel safe?

A: It removes the open port and puts a login in front of the app. It is only as safe as the Access policy behind it, the firewall on the origin, and your trust in Cloudflare, which decrypts the traffic. The mistakes section above lists the usual ways it goes wrong.

Q: Can zero trust replace a VPN for a small team?

A: For remote access to your own apps and servers, yes, and it usually reduces what is exposed. It does not replace a consumer VPN used to hide browsing from the local network, which solves a different problem.

Q: Does Cloudflare Tunnel hide my server's IP address?

A: It removes the need to publish it, since DNS points at the tunnel instead of the server. If the address was ever public, treat it as known and close inbound ports, so that the address leads nowhere even when someone has it.


Sources


System Alert

Is anything on your server still listening?

Run the Port Scan tool against your server's public IPv4 address and check that nothing you moved behind a tunnel still shows up as OPEN.