Cloudflare Tunnel and Zero Trust — Inbound-Free Remote Access
Cloudflare Tunnel publishes services on a private network through Cloudflare without opening inbound ports on the origin. cloudflared runs persistently on the origin, opens an outbound connection to Cloudflare, and uses that connection to provide access through Cloudflare Zero Trust (Cloudflare One) Access.
Three distinctions matter for an accurate understanding.
- A Tunnel and a connector are different things — the Tunnel is a logical object in Cloudflare; the connector is the
cloudflaredprocess running on the origin. - "Outbound-only" does not mean one-way — it means the connection is initiated outbound. Once established, data flows in both directions (a reverse tunnel).
- There is more than one access path — public hostnames (clientless) and private networks (Cloudflare One Client required) use different paths.
Overall architecture
The access flow is as follows.
- The user accesses a hostname on Cloudflare (for example,
app.example.com) over HTTPS. - Cloudflare Access redirects unauthenticated requests to the IdP login page.
- After authentication, Access evaluates policies (who is allowed, under which conditions).
- Only authorized requests are forwarded through the tunnel already established by
cloudflaredto the service inside the VM. - The service inside the VM listens on
127.0.0.1or a private IP and cannot be reached directly from the internet.
In other words, the only ingress from the internet is Cloudflare's edge, and the VM merely maintains an outbound connection to it.
Terminology
| Term | What it is | Role |
|---|---|---|
| Cloudflare Tunnel | A logical object in Cloudflare (identified by a UUID) | A persistent tunnel linking the origin to Cloudflare |
| connector | The cloudflared process running on the VM | Joins the Tunnel and opens outbound connections to Cloudflare |
| replica | An additional connector joined to the same Tunnel | Redundancy and rolling updates |
| route | A forwarding rule attached to a Tunnel | Public hostname / private IP or CIDR / private hostname |
| Access application | A Cloudflare configuration object | Adds authentication and authorization to a hostname or private destination |
| Access policy | Allow / Block / Bypass / Service Auth | Who can access. Deny by default |
| IdP | Entra ID, Google, Okta, etc. | Identity verification (OIDC / SAML) |
| Cloudflare One Client (WARP) | Client-side software | On-ramp for private network routes |
The feature set formerly called "Cloudflare for Teams" or "Cloudflare Zero Trust" is now branded Cloudflare One. The dashboard may still show a "Zero Trust" section.
Element 1: Cloudflare Tunnel and the connector
A Tunnel is a logical object; a connector is a process
A Tunnel created with cloudflared tunnel create or the dashboard is a logical connection endpoint that exists in Cloudflare. The cloudflared process running on the VM is the connector.
- Multiple connectors (replicas) can join one Tunnel.
- Each connector opens outbound connections to the nearest Cloudflare data center.
- Cloudflare forwards requests to one of the connectors joined to that Tunnel.
Outbound connection details
cloudflared opens connections to Cloudflare's edge as follows.
| Item | Detail |
|---|---|
| Primary protocol | QUIC (UDP 7844) |
| Fallback | HTTP/2 (TCP 7844) |
| Destination hostnames | region1.v2.argotunnel.com / region2.v2.argotunnel.com |
| Management API | api.cloudflare.com:443 |
| DNS | The system resolver (UDP/TCP 53) |
| Connection count | 4 per connector (spread across at least two data centers) |
--protocol defaults to auto. If UDP 7844 works, QUIC is used; otherwise cloudflared falls back to HTTP/2.
If you set --protocol quic while UDP 7844 is blocked, cloudflared will not switch to HTTP/2 and the connection fails. Leave it at auto when network requirements are unclear.
What "outbound-only" really means
"Outbound-only" means the connection is initiated from the VM toward Cloudflare. After the connection is established, requests flow from Cloudflare to the VM and responses flow from the VM to Cloudflare — it is bidirectional communication.
- No public listening port is needed on the VM.
- It works from behind NAT and stateful firewalls.
- No port forwarding or public IP address is required.
- However, outbound internet access itself is required (see below).
Remote management and tokens
The current recommendation is a remotely-managed Tunnel created in the dashboard. On the origin you only pass a token to cloudflared; routes and configuration are managed in Cloudflare.
| Aspect | Remotely managed (recommended) | Locally managed |
|---|---|---|
| Creation | Dashboard / API | cloudflared tunnel create |
| Startup | --token / --token-file | tunnel run <NAME> + config.yml |
| Route configuration | In Cloudflare | ingress in config.yml |
| Credentials | Tunnel token | cert.pem and credentials JSON |
| Best for | New deployments, central management across hosts | Keeping local configuration in Git |
You can tell which mode a host uses by checking whether the systemd ExecStart contains --token or --token-file, and whether ~/.cloudflared/config.yml or cert.pem exists.
# Example of installing as a service (the token is a secret)
sudo cloudflared service install <TUNNEL_TOKEN>
Alternatively, a systemd unit can start it as follows.
ExecStart=/usr/bin/cloudflared --no-autoupdate tunnel run --token-file /etc/cloudflared/token
Anyone who has the tunnel token can join a connector to that Tunnel. Restrict file permissions (for example, root:root 600) and never paste the token into Git or chat. If it leaks, rotate the token in Cloudflare.
Example health check
When cloudflared is running normally, you can check the service state and process as follows.
$ systemctl is-active cloudflared
active
$ ps -o args= -p <PID>
/usr/bin/cloudflared --no-autoupdate tunnel run --token-file /etc/cloudflared/token
$ ls -l /etc/cloudflared/token
-rw------- 1 root root ... /etc/cloudflared/token
At startup, the configuration is healthy if all of the following prechecks report status=pass.
INF | SUMMARY: Environment is healthy. cloudflared will use 'quic' as primary protocol. |
INF precheck component="DNS Resolution" details="DNS Resolved successfully" status=pass target=region1.v2.argotunnel.com
INF precheck component="UDP Connectivity" details="QUIC connection successful" status=pass target=region1.v2.argotunnel.com
INF precheck component="TCP Connectivity" details="HTTP/2 connection successful" status=pass target=region1.v2.argotunnel.com
INF precheck component="Cloudflare API" details="API is reachable" status=pass target=api.cloudflare.com:443
Because --no-autoupdate is set, cloudflared is not updated automatically. Update the binary and restart the service when needed.
How an outbound connection becomes bidirectional
The question "why can Cloudflare send requests later if the connection was opened outbound?" is best understood by separating the network layer from the application layer.
1. What the firewall sees
A stateful firewall or NAT keeps connection state keyed by the 5-tuple (source IP, source port, destination IP, destination port, protocol).
cloudflaredinitiates an outbound connection toregion1.v2.argotunnel.com:7844.- The firewall / NAT records an inside-to-outside flow.
- Packets returned by Cloudflare match that recorded flow.
- The stateful firewall allows them as return traffic for an existing connection.
In other words, a request from Cloudflare arrives as a packet on an established connection, not as a new inbound connection. From the firewall's perspective it is established / related traffic, not inbound. At no point does Cloudflare open a new TCP connection to the origin.
2. Tunnel registration (control plane)
cloudflared authenticates to Cloudflare with a token (or locally-managed credentials) and registers itself as a connector for a specific Tunnel. Cloudflare then maintains a mapping from Tunnel UUID to the currently connected connectors.
- Multiple connectors can register for the same Tunnel.
- When forwarding a request, Cloudflare selects one of the registered connectors.
- If a connection drops, its registration is removed and another connector is selected.
3. Multiplexing (data plane)
Multiple requests are multiplexed as streams over one QUIC or HTTP/2 connection.
- HTTP/2: multiple streams over one TCP connection.
- QUIC: independent streams over one UDP connection, without TCP head-of-line blocking.
- WebSockets and TCP-based protocols are carried as streams over the tunnel.
- When UDP is carried over the tunnel, it uses QUIC datagrams.
Cloudflare Tunnel follows a reverse HTTP-like model in which the origin is the transport client. In ordinary HTTP/2 the client initiates requests; in the tunnel the roles are reversed and Cloudflare sends requests over the established connection. The origin therefore does not need to open a new inbound connection.
4. What happens at the origin
cloudflared opens a new local connection to 127.0.0.1:3000, 10.0.0.50:5432, or another local/private destination. This is not an inbound connection from the internet; it is a local or private connection initiated by the cloudflared process.
- The service can listen on
127.0.0.1. - No internet-facing listening port is required.
- No host firewall inbound rule is required.
5. Sequence
6. Why you can say "no inbound port is opened"
| Layer | What happens |
|---|---|
| L3/L4 | An outbound flow from cloudflared to Cloudflare is established; NAT / firewall keeps its state |
| Tunnel control | cloudflared authenticates with the tunnel token and registers as a connector |
| Multiplexing | Cloudflare creates a stream on the existing connection and sends the request over it |
| Application | cloudflared connects to the local service and returns the response |
"No inbound rule" means no new connection is accepted from the internet. It does not contradict application data flowing in both directions over the established outbound connection.
cloudflared sends keepalives so that NAT idle timeouts do not drop the connection. If a connection is lost, it reconnects with backoff, and other connectors can continue serving requests in the meantime.
Element 2: Routes (where traffic is forwarded)
Joining a Tunnel does not decide which requests go where. Routes do that. There are two main kinds.
Public hostname
A public hostname route associates a DNS record in Cloudflare with the Tunnel.
- DNS: point the CNAME for
app.example.comat<TUNNEL_UUID>.cfargotunnel.com(Proxied). - Tunnel ingress: map
app.example.comto a destination such ashttp://localhost:3000. - Users can access it with a browser alone (no Cloudflare One Client).
- However, unless Access is configured, that hostname is a publicly reachable application.
User → Cloudflare edge → Access → Tunnel → cloudflared → localhost:3000
Private network route
A private network route reaches private IPs, CIDRs, or private hostnames through the Tunnel.
- Example: route
10.0.0.0/24to the VM's private network. - The user needs the Cloudflare One Client (WARP).
- The client runs in Traffic and DNS mode, and a Gateway resolver policy resolves private hostnames.
- A normal browser cannot reach
http://10.0.0.50directly.
User → Cloudflare One Client → Cloudflare edge → Access → Tunnel → cloudflared → 10.0.0.50
Public hostname vs. private route
| Aspect | Public hostname | Private network route |
|---|---|---|
| User software | Browser only (clientless) | Cloudflare One Client (WARP) or Cloudflare WAN |
| DNS | Public DNS CNAME | Gateway resolver / Local Domain Fallback / private hostname |
| Access application type | Self-hosted public | Self-hosted private destination / Infrastructure |
| Typical use | Web apps, APIs | SSH, databases, internal IP ranges, internal hostnames |
| Origin exposure | Published through Cloudflare | Stays private |
Routes and Access are separate
- A route decides where traffic goes.
- An Access application / policy decides who can send it.
Creating a route does not add authentication. You must also configure an Access application and policy.
Virtual networks
When IP ranges overlap — for example, production and staging both use 10.0.0.0/24 — use Virtual Networks to separate routing domains. Assign each Tunnel route to a virtual network and select the virtual network on the Cloudflare One Client. If ranges do not overlap, one Tunnel can carry multiple routes.
Element 3: Zero Trust Access
The Zero Trust idea
Traditional network security trusted anything inside the corporate network. Zero Trust abandons that boundary model and verifies identity and context on every request.
In the Cloudflare context, responsibilities are divided as follows.
| Product | What it protects | Main functions |
|---|---|---|
| Cloudflare Access | Access to applications | IdP authentication, policy evaluation, JWT issuance |
| Cloudflare Gateway | Traffic leaving devices | DNS / HTTP / network policies, TLS inspection |
| Cloudflare Tunnel | The path to the origin | Outbound connections, routing |
| Cloudflare One Client (WARP) | Device-side on-ramp | Private routes, DNS, forwarding to Gateway |
Access handles application authentication and authorization; Gateway handles traffic filtering. They are different products and can be used together.
Access application types
| Type | Cloudflare One Client | Target |
|---|---|---|
| Self-hosted public | Not required (clientless) | Web apps and APIs on public hostnames |
| Self-hosted private destination | Usually required | Private IPs / CIDRs / hostnames |
| Infrastructure | Required | Protocol-level control such as SSH |
Users of a public-hostname application only need a browser to log in. Private IPs and SSH require the Cloudflare One Client on the device.
Policy evaluation model
An Access policy combines an action with rules.
| Element | Meaning |
|---|---|
| Action | Allow / Block / Bypass / Service Auth |
| Include | OR condition. Satisfying any one is enough |
| Require | AND condition. All must be satisfied |
| Exclude | NOT condition. A match denies access |
Key properties:
- Deny by default: users who match no Allow policy are denied.
- Every policy needs at least one Include rule.
BypassandService Authare evaluated first; thenBlock/Alloware evaluated top to bottom.- Once a user matches Allow or Block, evaluation stops. Later policies cannot override the decision.
Bypassdisables Access enforcement, so use it only in narrow cases.
Authentication flow
Validating the Access JWT
Access adds a Cf-Access-Jwt-Assertion header to authorized requests forwarded to the origin. Browser flows may also use the CF_Authorization cookie, but validating the header JWT at the origin is the reliable approach.
Validation steps:
- Read the JWT from the
Cf-Access-Jwt-Assertionheader. - Fetch the public keys (JWKS) from
https://<TEAM_NAME>.cloudflareaccess.com/cdn-cgi/access/certs. - Select the key matching the JWT's
kid. - Verify the RS256 signature.
- Validate
iss(team domain),aud(the application's AUD tag), andexp(expiration).
Access rotates its signing keys periodically, so do not hard-code them — fetch them dynamically from the JWKS endpoint. Without aud validation, a token issued for another Access application could be replayed.
Requests through the Tunnel have passed through Access, but if the origin is reachable by another path (for example, inside the private network), a request with a forged header could arrive. Validating the JWT at the origin provides defense in depth.
Service-to-service access
For non-human access such as CI/CD or batch jobs, use service tokens or mTLS. The Service Auth action in an Access policy configures authentication that does not go through an IdP.
Why no inbound rules are needed
Network-layer reason
cloudflared initiates the connection from the VM to Cloudflare. Many cloud security groups and stateful firewalls allow return traffic for an outbound-initiated connection automatically.
As a result, the following are unnecessary.
- Inbound allow rules for TCP 443 / 22 from the internet
- A public IP address
- Port forwarding
- A load balancer to publish a reverse proxy to the internet
Security implications
- The origin IP is hidden: users connect only to Cloudflare's edge.
- The attack surface is reduced: there is no internet-facing listening port on the VM.
- Authentication happens before the origin: Access completes IdP authentication and policy evaluation before forwarding.
- DDoS and TLS termination are absorbed by Cloudflare: WAF and rate limiting can be added if needed.
Pitfalls of "no inbound needed"
| Misconception | Reality |
|---|---|
| Outbound-only means data flows one way | The connection is initiated outbound; after establishment it is bidirectional |
| No inbound needed means no host firewall | Bind the origin to 127.0.0.1 and keep host-level protections |
| Creating a Tunnel makes it secure | Without an Access policy, it is a public application |
| Configuring Access also creates routes | Routes and Access applications are configured separately |
| A Tunnel is a VPN replacement | It is an application/route-level reverse proxy. For L3 VPN, consider Cloudflare WAN / Mesh |
| The token is just a setting | It is a bearer credential that lets a connector join the Tunnel |
Security comparison with VPN
Scope of the comparison
"Cloudflare Tunnel vs. VPN" is not a like-for-like comparison.
- A VPN provides L3/L4 network connectivity.
- Cloudflare Tunnel is an application/route-level reverse proxy / tunnel, and Access handles user authentication and authorization.
- The meaningful comparison is therefore "traditional VPN" vs. "Cloudflare Tunnel + Access".
- A Tunnel alone does not authenticate users, so it is not a VPN replacement by itself.
This comparison assumes a traditional VPN (IPsec / SSL VPN). Some modern VPN products include ZTNA-like capabilities, so strength varies by product.
Comparison table
| Aspect | Traditional VPN | Cloudflare Tunnel + Access |
|---|---|---|
| Unit of access | Network (L3) | Application / route (L7 for public hostnames, L3/L4 equivalent for private routes) |
| Authentication | At VPN connection time | Per application via IdP; MFA via IdP, device posture via Cloudflare One Client |
| Authorization | Routing / firewall at network granularity | Access policies per application; deny by default |
| Exposure | Public VPN gateway endpoint | No inbound on the origin; the Cloudflare edge is the public surface |
| Lateral movement | Users can often reach a broad internal network after connecting | Only the applications / routes explicitly allowed |
| Auditing | Mostly connection logs | Access authentication and authorization decision logs |
| Client | VPN client | Browser (public hostname) or Cloudflare One Client |
| Protocols | All IP traffic | HTTP via public hostnames; TCP/UDP via private routes / WARP |
| Encryption | IPsec / TLS | QUIC / TLS. User TLS is commonly terminated at Cloudflare |
| Failure point | VPN appliance | Cloudflare + connector + origin |
| Operations | Appliance patching / certificates | cloudflared updates / tokens / policies |
| Third-party dependency | Small if self-hosted | Significant reliance on Cloudflare |
How to decide which is "stronger"
- For least privilege, Tunnel + Access has the advantage. Authorization is per application rather than per network. A VPN often gives broad reach after connection, increasing the blast radius of a compromise.
- Authentication strength depends on the IdP. Access can use the IdP's MFA and passkeys, plus device posture from the Cloudflare One Client. A VPN can also be strong with mTLS, certificates, and MFA. The product name does not decide this; the configuration does.
- For reducing exposure, Tunnel has the advantage. A VPN gateway must listen on the internet. A Tunnel has no inbound listener on the origin.
- For third-party dependency and data visibility, a VPN can have the advantage. Cloudflare terminates user TLS at its edge, so requirements that do not fully trust Cloudflare need application-layer end-to-end encryption.
- For broad L3 connectivity and legacy protocols, VPN / Cloudflare WAN / Mesh are a better fit. Tunnel + Access is aimed at publishing individual applications.
Summary: Choose Tunnel + Access when per-application least privilege and a smaller public surface matter most; choose VPN / Cloudflare WAN / Mesh for broad L3 connectivity or legacy protocols. In either case, strength depends on configuration: IdP MFA, device management, authorization granularity, auditing, and key management.
Factors that determine strength
| Factor | Weak example | Strong example |
|---|---|---|
| Authentication | Password only | Passkeys / hardware keys + MFA |
| Authorization | Every employee can reach every app | Group-based least privilege, deny by default |
| Devices | Any device | Device posture / EDR / encryption required |
| Exposure | VPN gateway + public origin | No origin inbound + Access |
| Auditing | Connection logs only | Authentication / authorization logs + SIEM |
| Key management | Static tokens / shared accounts | Short-lived credentials / rotation / service tokens |
| Failure handling | Single VPN appliance | Multiple connectors / multiple paths |
Cloudflare Tunnel only provides a path; it does not authenticate or authorize users. A public hostname without Access is a publicly reachable application.
Similar services on Azure and AWS
What "same protocol" means
Cloudflare Tunnel uses QUIC (UDP 7844) as its primary transport and HTTP/2 (TCP 7844) as a fallback. Within the scope of this research, no Azure or AWS managed service has an origin-side agent that connects to the cloud over the same QUIC/7844 wire protocol.
However, they share the same reverse-tunnel connection model: the origin initiates an outbound connection, and the cloud sends requests over that established connection. The services below follow that model.
Comparison table
| Cloud | Service | Transport | Origin side | Authentication / authorization | Primary use |
|---|---|---|---|---|---|
| Azure | Microsoft Entra Private Access (Private Network Connector) | TLS over TCP 443 (80 for CRL) | Connector on Windows Server | Entra ID + Conditional Access | ZTNA for apps and private networks |
| Azure | Azure Arc SSH access | TCP 443 | Azure Connected Machine agent | Entra ID / Azure RBAC | SSH to Arc-enabled servers |
| Azure | Azure Relay Hybrid Connections / App Service Hybrid Connections | WebSocket over TCP 443 (TLS 1.2) | Hybrid Connection Manager / listener | SAS keys | Relay to on-premises services |
| Azure | Azure VPN Gateway | IPsec/IKE / SSL | VPN gateway | Certificates / RADIUS, etc. | Site-to-site and P2S L3 connectivity |
| AWS | AWS Verified Access | HTTPS (client to endpoint) | None (internal load balancer / ENI in the VPC) | IAM Identity Center / OIDC / SAML + device posture | ZTNA for web and TCP applications |
| AWS | AWS Systems Manager Session Manager | HTTPS/TLS 1.2 over TCP 443 | SSM Agent | IAM | Administrative access to EC2 and on-premises nodes, port forwarding |
| AWS | AWS Client VPN / Site-to-Site VPN | IPsec / TLS | VPN endpoint | Certificates / AD, etc. | L3 connectivity |
Microsoft Entra Private Access
- A Private Network Connector on Windows Server opens outbound connections to
*.msappproxy.net/*.servicebus.windows.netover TCP 80 / 443. - The connector is outbound-only. No inbound ports are required, and traffic flows both ways after a session is established.
- Connector groups isolate applications, and at least two connectors per group are recommended for HA.
- Users connect through the Global Secure Access client, and Entra ID authentication, Conditional Access, and device posture can be applied.
- It supports not only HTTP/HTTPS but also TCP/UDP private applications.
Difference from Cloudflare Tunnel: Cloudflare uses cloudflared on Linux, containers, or on-premises hosts, and public hostnames are clientless. Entra Private Access is centered on a Windows Server connector and client-side software.
Azure Arc SSH access
- The Azure Connected Machine agent opens an outbound connection to Azure over TCP 443.
az ssh arcand similar tools provide SSH access to Arc-enabled servers without a public IP or inbound SSH port.- It can be combined with Entra ID login and RBAC.
- It is for administrative access only; it does not publish web applications or provide application-level authorization like Access.
Azure Relay Hybrid Connections / App Service Hybrid Connections
- With Azure Relay Hybrid Connections, an on-premises listener application opens an outbound WebSocket over TCP 443 to Azure Relay.
- With App Service Hybrid Connections, the Hybrid Connection Manager (HCM) connects outbound to Azure Relay on port 443.
- A cloud sender posts to the Relay endpoint, and the Relay bridges the data over the existing bidirectional socket. No inbound port is needed.
- It authenticates with TLS 1.2 and SAS keys.
- App Service Hybrid Connections connects App Service to an on-premises TCP endpoint. It does not support UDP or dynamic ports.
Difference from Cloudflare Tunnel: Relay is a transport and does not provide user authentication or application-level policies like Access. Cloudflare becomes ZTNA when combined with Access.
AWS Verified Access
- It consists of a Verified Access instance, groups, endpoints, and trust providers.
- Endpoints connect to an internal load balancer, network interface, network CIDR, or RDS in the VPC. Applications do not need public IPs or inbound internet ports.
- It evaluates Cedar policies per request and checks IdP identity and device posture.
- In addition to HTTP/HTTPS web apps, TCP applications (SSH / RDP, etc.) can be handled with network interface or CIDR endpoints.
- It logs every access attempt.
Difference from Cloudflare Tunnel: Verified Access does not place an agent on the origin; AWS places a reverse proxy inside the VPC. It assumes AWS VPC / ALB / ENI and is not intended to publish VMs in other clouds or on-premises as-is.
AWS Systems Manager Session Manager
- The SSM Agent opens outbound HTTPS 443 connections to
ssm.<region>.amazonaws.com,ssmmessages.<region>.amazonaws.com, andec2messages.<region>.amazonaws.com. - No public IP, bastion host, or inbound SSH port is required.
- IAM authorizes access, and sessions can be logged to CloudTrail / S3 / CloudWatch Logs.
- It supports shell access, SSH / RDP port forwarding, and tunneling.
Difference from Cloudflare Tunnel: It is dedicated to administrative sessions and is not used to publish web applications or provide application-level authorization to end users. Cloudflare can publish applications when combined with Access.
Difference from VPN services
Azure VPN Gateway, AWS Client VPN, and AWS Site-to-Site VPN provide network-level (L3) connectivity. A VPN gateway must listen on the internet, and users can often reach a broad network after connecting. When per-application least privilege or clientless access is required, Tunnel + Access, Entra Private Access, or Verified Access is a better fit.
Choosing a service
| Requirement | Candidate |
|---|---|
| Publish a VM in any cloud or on-premises, per application | Cloudflare Tunnel + Access |
| Entra ID-centric environment with a Windows Server connector | Microsoft Entra Private Access |
| SSH to Azure Arc-enabled servers | Azure Arc SSH access |
| Connect an Azure app to an on-premises TCP service | Azure Relay / App Service Hybrid Connections |
| ZTNA for web / TCP apps inside AWS | AWS Verified Access |
| Administrative access to AWS EC2 / on-premises nodes | AWS Systems Manager Session Manager |
| Site-to-site or all-protocol L3 connectivity | VPN / Cloudflare WAN / Mesh |
Cloudflare Tunnel's strength is that it is cloud-agnostic and runs on Linux, containers, or on-premises hosts; public hostnames are clientless, while private routes use the Cloudflare One Client. Similar Azure and AWS services are optimized for their own ecosystems (Entra ID, AWS VPC / IAM).
Security weaknesses and countermeasures
Threat model
| Asset / weakness | Threat | Impact | Main countermeasures |
|---|---|---|---|
| Tunnel token | Leak or theft | An attacker can add a connector and join the Tunnel | File mode 600, secret management, regular rotation, force-disconnect on leak |
| Cloudflare account | Account takeover | Routes / Access policies can be modified | SSO + hardware keys, least-privilege roles, scoped API tokens, audit logs |
| Access policies | Misconfiguration / Bypass abuse | Unauthenticated access | Deny by default, Access on every hostname, avoid Bypass, regular review |
| Origin | Direct reachability by another path | Access bypass | Bind to 127.0.0.1, host firewall, network segmentation, JWT validation |
| IdP / sessions | Phishing / session theft | Impersonation | Passkeys / FIDO2, conditional access, short sessions, revocation |
| cloudflared / host | Compromise / supply chain | Lateral movement inside the tunnel | Signature verification, updates, least privilege, dedicated user, EDR |
| Data path | TLS termination at Cloudflare | Third-party visibility | Application-layer end-to-end encryption, choose the path based on requirements |
| Availability | Cloudflare / egress outage | Loss of access | Multiple connectors, monitoring, alternative path, runbook |
| Logs / auditing | Insufficient logging | Delayed detection | Access / Gateway / cloudflared logs to SIEM |
| Private routes | Overly broad CIDRs | Excessive reach from WARP devices | Minimize CIDRs, Virtual Networks, Gateway policies |
| SSH | Static keys / shared accounts | Key leak / no audit trail | Short-lived certificates, Infrastructure Access, command logging |
1. Tunnel token leakage
The tunnel token is a bearer credential. Anyone who has it can join a connector to the Tunnel.
- Putting
--tokendirectly on the command line exposes it inpsoutput and shell history. Use--token-fileor a secret manager. - Restrict the token file to
root:root 600or similar. - Never put it in Git, CI logs, chat, or container images.
- Rotate it regularly. Existing connectors keep working with the old token, so install the new token on half the replicas, wait about 10 minutes, then install it on the rest for a zero-downtime rotation.
- On a leak, refresh the token, force-disconnect all Tunnel connections, and reinstall the legitimate replicas with the new token.
- Monitor the dashboard for unexpected connectors.
2. Cloudflare account compromise
The Cloudflare account is the control plane. An attacker who takes it over can add routes or change Access policies.
- Require SSO / hardware keys / MFA on the Cloudflare account itself.
- Minimize administrator roles and separate Tunnel, DNS, and Access administration.
- Scope API tokens to specific resources and set expiration.
- Ship audit logs to a SIEM and alert on Tunnel / Access / DNS changes.
- Separate production and non-production Cloudflare accounts.
3. Access policy misconfiguration
Access denies by default, but an overly broad Allow defeats that.
- Forgetting an Access application on a public hostname leaves it publicly accessible.
- An Allow rule for
Everyoneor the entire corporate domain effectively grants organization-wide access. Bypassdisables Access enforcement and does not log requests. Avoid it as a rule.- Wildcards and path-based rules use most-specific matching. Verify that only the intended application is covered.
- Use group-based least privilege and review policies quarterly.
- Test with an unauthorized user to confirm access is actually denied.
- Validate the JWT at the origin, or enable Protect with Access on the Tunnel, to prevent bypass.
4. Direct reachability of the origin
Any path that bypasses the Tunnel also bypasses Access.
- Bind origin services to
127.0.0.1or a private interface. - Use a host firewall to reject unnecessary inbound traffic.
- Do not publish the same service through another load balancer, public IP, or network path.
- If the origin is reachable from inside the private network,
Cf-Access-Jwt-Assertioncan be spoofed. Validate the JWT at the origin. - Do not let other reverse proxies or applications trust
Cf-Access-*headers blindly. Strip and re-add them at trust boundaries.
5. IdP / session compromise
Access authentication strength depends on the IdP.
- Use phishing-resistant MFA such as passkeys / FIDO2.
- Apply conditional access based on location, device, and risk.
- Keep session lifetimes short and revoke sessions on compromise.
- Avoid shared accounts; use service tokens for service-to-service access.
- Monitor suspicious sign-ins and deny events.
6. cloudflared / host compromise
If cloudflared or the host is compromised, an attacker can move laterally to services reachable through the tunnel.
- Keep
cloudflaredup to date. With--no-autoupdate, define a manual update process. - Use official packages or signed binaries and verify their source.
- Run as a dedicated user and restrict who can edit the token file and systemd unit.
- Deploy EDR / log monitoring on the host and disable unnecessary services.
- Minimize the local services that
cloudflaredcan reach.
7. Data path and third-party dependency
Cloudflare terminates user TLS at its edge, so Cloudflare can potentially access application data (and sees plaintext if the origin uses HTTP).
- Use HTTPS to the origin and keep
noTLSVerifyset tofalse. - When using a private CA, configure
caPool/originServerNamecorrectly. - If Cloudflare must not be trusted with the data, encrypt at the application layer end to end. mTLS authenticates the origin but does not remove visibility from TLS termination at the Cloudflare edge.
- Access logs contain metadata about who accessed which application and when. Check data residency and audit requirements.
8. Availability
If the Tunnel goes down, neither Access nor the origin is reachable.
- Run multiple connectors on separate hosts in production.
- Use Cloudflare Load Balancer for advanced failover on public hostnames.
- Monitor Cloudflare / egress / DNS failures and maintain a runbook.
- Do not make the Tunnel the only path for administrative access. Keep a break-glass path if needed.
9. Logging and detection
- Collect Access authentication and authorization logs, Gateway traffic logs,
cloudflaredlogs, and Cloudflare audit logs. - Ship them to a SIEM and alert on:
- A new connector joining
- Tunnel token rotation / forced disconnect
- Access policy, route, or DNS changes
- A spike in denies or access from unusual locations or devices
- Set log retention to match compliance requirements.
10. Private routes and SSH
- Minimize private route CIDRs. Avoid broad routes such as
0.0.0.0/0. - Separate overlapping IP ranges with Virtual Networks.
- Combine with Cloudflare One Client device posture, Split Tunnels, and Gateway policies.
- For SSH, avoid shared static keys. Use Infrastructure Access with short-lived certificates, command logging, and privileged access management.
- Enable host key verification.
Configuration checklist
| Item | What to verify |
|---|---|
| Public hostnames | Every one has an Access application |
| Access policies | Group-based least privilege; no Everyone or excessive wildcards |
| Bypass | Not used as a rule |
| Origin | Bound to 127.0.0.1 / private; no direct path to it |
| JWT | Origin validation or Protect with Access enabled |
| Token | 600 / secret manager; not in command lines or Git |
| Rotation | Procedure and owner defined; forced-disconnect procedure exists |
| Cloudflare account | MFA / least privilege / audit logs / scoped API tokens |
cloudflared | Up to date; signature / package verified; dedicated user |
| Redundancy | Multiple connectors on separate hosts; monitoring and alerts |
| Logs | Access / Gateway / cloudflared / audit logs shipped to a SIEM |
| TLS | noTLSVerify is false; application-layer encryption if needed (mTLS authenticates the origin) |
| Private routes | CIDRs minimized; Virtual Networks / Gateway policies in place |
| SSH | Short-lived certificates / command logging / host key verification |
Origin-side network requirements
If egress is restricted by cloud security groups, network ACLs, or firewalls, allow the following.
| Direction | Protocol / port | Destination | Purpose |
|---|---|---|---|
| Outbound | UDP 7844 | region1.v2.argotunnel.com / region2.v2.argotunnel.com | QUIC (primary) |
| Outbound | TCP 7844 | Same as above | HTTP/2 (fallback) |
| Outbound | TCP 443 | api.cloudflare.com | Management API / precheck |
| Outbound | UDP/TCP 53 | DNS resolver | Name resolution |
| Inbound | None | — | Not required |
Notes:
- Allow by hostname where possible. Cloudflare does not guarantee fixed CIDRs, so hard-coding IP addresses may break when they change.
- A VM in a private subnet needs a NAT gateway or outbound proxy for internet access. A public IP is not required.
- Many environments allow all egress by default, but environments that restrict it must add the rules explicitly.
- In IPv6-only environments, also check
--edge-ip-version.
Operations
Checking service status
systemctl status cloudflared
journalctl -u cloudflared -n 100 --no-pager
journalctl -u cloudflared -f
Prechecks run at startup and verify DNS, UDP (QUIC), TCP (HTTP/2), and management API reachability. Environment is healthy and suggested_protocol=quic indicate a healthy state.
Redundancy
- One connector opens four connections to at least two data centers.
- Adding replicas to the same Tunnel increases the total number of connections.
- To survive host failure, run replicas on separate hosts.
- Cloudflare forwards to the nearest replica and retries others on failure. It is not strict round-robin.
- For advanced load balancing or health-check-based failover on public hostnames, use Cloudflare Load Balancer. Private hostname routes are not compatible with Load Balancer; use replicas instead.
Updates
With --no-autoupdate, cloudflared does not update itself. Update the binary or package and restart the service. Updates can interrupt connections, so rolling updates with replicas are preferable.
Monitoring
--metricsexposes Prometheus-format metrics.--log-directoryenables log rotation (1 MB × 5 files).- The Cloudflare dashboard shows Tunnel status and analytics.
- Keep
cloudflaredlogs and application logs separately searchable on the origin.
Least privilege
cloudflareddoes not listen on privileged ports, so it can often run as a dedicated user.- Make the tunnel token file readable only by root (for example,
600). - Bind origin services to
127.0.0.1to reduce reachability from inside the private network. - Manage Access policies by group rather than enumerating individual email addresses.
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| Cloudflare 1033 | The Tunnel is not connected | systemctl status cloudflared, egress 7844, token, DNS |
| 502 / 530 | The Tunnel is healthy but the origin is unreachable | Ingress service URL, application port, host firewall |
| 403 | Access deny-by-default or policy mismatch | Access application hostname, Allow policy, IdP group |
| 404 | Route / ingress mismatch | Public hostname, CNAME, Tunnel ingress configuration |
| Login loops | Cookie / team domain / application mismatch | CF_Authorization, Access application settings, browser cookies |
| QUIC fails but HTTP/2 works | UDP 7844 is blocked | Whether auto is used and --protocol quic is not forced |
| SSH fails | sshd / route / client-side path issue | sshd listener, ingress, cloudflared access ssh or Cloudflare One Client, Access policy |
| Token cannot be read | File permissions / runtime user | Owner and mode of /etc/cloudflared/token, systemd user |
For remotely-managed Tunnels, local management commands such as cloudflared tunnel info may not work. In that case, check the Tunnel status in the dashboard and the journalctl logs.
Understanding summary
| Point | Explanation |
|---|---|
| Connection direction | cloudflared (the connector) initiates an outbound connection to Cloudflare. The Tunnel is a logical object in Cloudflare |
| Authentication | Access performs IdP authentication and policy evaluation. The user-side path differs for public hostnames vs. private destinations |
| Inbound | No inbound rules are needed on the origin. Egress for 7844 / 443 / DNS is still required |
| Data direction | Outbound-only describes the connection initiation; after establishment, communication is bidirectional |
Design checklist
- Does the user access with only a browser, or with the Cloudflare One Client? → This depends on whether it is a public hostname or a private route.
- Is the target a web app or SSH / a database? → The application type and client requirements differ.
- Who does the Access policy allow? → Access denies by default; users who match no Allow rule cannot enter.
- Where is the origin bound? → If it listens on
127.0.0.1, it is not directly reachable from the internet. - Who can read the token? → It is a bearer credential; check file permissions and rotation.
Related technologies
| Technology | When it is needed |
|---|---|
| Cloudflare One Client (WARP) | Accessing private IPs / CIDRs / hostnames |
| Cloudflare Gateway | Enforcing policies on device DNS / HTTP / network traffic |
| Cloudflare WAN / Mesh | Site-to-site or L3 private network connectivity |
| Infrastructure Access | Short-lived SSH certificates, command logging, privileged access management |
| Browser Rendering | Browser-based SSH / RDP / VNC without client software |
| Cloudflare Load Balancer | Health-checked failover across multiple Tunnels |
| Service tokens / mTLS | Non-human access from CI/CD and service-to-service calls |
| Entra ID | Usable as an Access IdP (OIDC / SAML) |
Comparison with Azure
| Goal | Closest Azure concept | Cloudflare setup |
|---|---|---|
| Private connectivity to a VM | VPN Gateway / ExpressRoute | Cloudflare Tunnel (per application) / Cloudflare WAN (per site) |
| Administrative SSH / RDP | Azure Bastion | Access + Tunnel / Infrastructure Access / Browser Rendering |
| Network ACLs | NSG / Azure Firewall | Access policies + Gateway |
| Identity platform | Entra ID | IdP (Entra ID can be used) |
These are not exact equivalents. Azure Bastion is an administrative jump host, while Cloudflare Access is a per-application authentication proxy; they protect different layers.
References
Cloudflare
- Cloudflare Tunnel
- Tunnel connectivity prechecks
- Tunnel with firewall
- Tunnel availability
- cloudflared run parameters
- Tunnel permissions
- Origin parameters
- Choose an application type
- Access policies
- Validating Access JWT
- SSH with Cloudflare Tunnel
- Private hostname routes
- Tunnel virtual networks
- Reverse HTTP (IETF 118)
Azure
- Microsoft Entra private network connectors
- SSH access to Azure Arc-enabled servers
- Azure Relay
- App Service Hybrid Connections