Security

Cloudflare SASE: Seven Protections and Where Tunnel Fits

Cloudflare SASE bundles seven protections into one edge. What each layer does, and why a Tunnel plus Access setup for internal apps is textbook ZTNA.

July 30, 2026
15 min read
Cloudflare SASE: Seven Protections and Where Tunnel Fits

SASE (Secure Access Service Edge) is the idea, coined by Gartner in 2019, that networking and network security should stop being separate boxes in a data center and instead converge into a single cloud-delivered service. Instead of backhauling every remote worker through a VPN concentrator so a stack of appliances can inspect their traffic, users and offices connect to the nearest edge location of a global network, and every security policy is enforced right there, close to the user, for all traffic at once.

Cloudflare's implementation of this model is Cloudflare One. It runs on the same global anycast network as the rest of Cloudflare, which means every data center runs every service: a request is authenticated, filtered, inspected, and logged in a single pass at whichever location the user happens to hit.

Every SASE platform is really two products fused together. One half is network-as-a-service: the plumbing that gets packets from users, devices, offices, and servers onto the provider's network. In Cloudflare's case that is the WARP device client, Cloudflare Tunnel for connecting servers and private networks without opening inbound ports, and Magic WAN and Magic Transit for whole-site and whole-network connectivity.

The other half is the security stack, often called SSE (Security Service Edge), that sits on top of that plumbing and decides what traffic is allowed to do. This is where the actual protections live, and it is the half people mean when they ask what SASE protects against.

Cloudflare One ships seven distinct protection services. Each one answers a different question about your traffic, and they compose: the same request can pass through several of them in one trip through the edge.

ProtectionWhat it protectsCloudflare product
ZTNA (Zero Trust Network Access)Access to each internal app, checked per user, per device, per requestCloudflare Access
SWG (Secure Web Gateway)Outbound traffic: DNS, HTTP, and network-level filtering of what devices reachCloudflare Gateway
CASB (Cloud Access Security Broker)SaaS tenants: misconfigurations, risky sharing, exposed filesCloudflare CASB
DLP (Data Loss Prevention)Sensitive data (PII, credentials, source code) leaving in transitCloudflare DLP
RBI (Remote Browser Isolation)The endpoint browser, by rendering untrusted pages at the edge insteadBrowser Isolation
Email SecurityInboxes: phishing, business email compromise, malicious attachmentsCloud Email Security
FWaaS (Firewall as a Service)Network traffic, with firewall rules enforced at the edge instead of on hardwareMagic Firewall

Alongside these seven, Cloudflare One also ships Digital Experience Monitoring (DEM), which observes connectivity and performance rather than blocking anything, so I count it as observability rather than a protection layer.

One edge, seven protections
The security half of Cloudflare SASE, carried by the network-as-a-service half

Diagram: One edge, seven protections.

  • ZTNA (Access · per-app identity checks)
  • Secure Web Gateway (Gateway · DNS, HTTP, network)
  • CASB (SaaS posture scanning)
  • DLP (data in transit)
  • Browser Isolation (pages rendered at the edge)
  • Email Security (phishing · BEC · attachments)
  • FWaaS (Magic Firewall)
  • Cloudflare One (single-pass SASE edge)
  • Network services (WARP · Tunnel · Magic WAN)
  • ZTNA to Cloudflare One
  • Secure Web Gateway to Cloudflare One
  • CASB to Cloudflare One
  • DLP to Cloudflare One
  • Browser Isolation to Cloudflare One
  • Email Security to Cloudflare One
  • FWaaS to Cloudflare One
  • Network services carries the traffic to Cloudflare One

The guide that makes up the rest of this post publishes internally self-hosted applications through Cloudflare Tunnel and locks them behind identity, device posture, and access policies. It is worth being precise about the category: Cloudflare Tunnel itself is not a protection, it is plumbing from the network-as-a-service half. It creates an outbound-only connection from your server to Cloudflare's edge, so the app needs no open inbound ports and no public IP exposure.

The protection wrapped around that tunnel is ZTNA. Every request to the app's hostname is intercepted by Cloudflare Access, which verifies who the user is against the identity provider, checks that their device is enrolled and passing posture checks, and only then lets the request through to the tunnel. No user or device is trusted by default, access is evaluated per application and per request, and the private network is never exposed. That is the definition of Zero Trust Network Access.

The ZTNA request path this guide builds
Drag, pan, and zoom: identity and posture are checked at the edge before anything reaches the tunnel

Diagram: The ZTNA request path this guide builds.

  • External caller (/webhook paths only)
  • Team member (WARP client enrolled)
  • Google IdP (OAuth 2.0 + PKCE)
  • Cloudflare Access (email allow-list + posture)
  • Cloudflare Tunnel (no inbound ports)
  • cloudflared (Docker, shared network)
  • Internal app (n8n on the Docker network)
  • Team member request to Cloudflare Access
  • Cloudflare Access verify identity to Google IdP
  • Cloudflare Access allowed to Cloudflare Tunnel
  • Cloudflare Tunnel proxied request to cloudflared
  • cloudflared service DNS name to Internal app
  • External caller bypass policy to Cloudflare Access

This guide covers the end-to-end setup for protecting internally self-hosted applications behind a Cloudflare tunnel, enforced by Zero Trust access policies. It covers identity provider integration, tunnel configuration, device posture, access policies, and client deployment via Docker.

Path: Integrations > Identity Providers

  1. 01
    Add the provider

    Click Add identity provider and select Google.

  2. 02
    Retrieve credentials

    Retrieve the Client ID and Client Secret from Google Cloud Console. The OAuth 2.0 app type must be Web Application.

  3. 03
    Enable PKCE

    Enable Proof Key for Code Exchange (PKCE): ON.

  4. 04
    Save and verify

    Click Save, then use the Test button to verify the connection.

Path: Networks > Connectors

  1. 01
    Choose the connector type

    Select tunnel type: Cloudflared.

  2. 02
    Name it

    Name the tunnel and click Next.

  3. 03
    Copy the token

    Copy the generated cloudflared tunnel token. This is needed for deployment.

  4. 04
    Continue

    Click Next to proceed to the application route setup.

This step maps a subdomain to the internal service that should be tunneled.

Hostname fieldValue
SubdomainThe subdomain for accessing the service
DomainSelectable from the dropdown; these are domains connected to Cloudflare
PathLeave empty to protect all paths, or specify a sub-path
Service fieldValue
TypeHTTP, for services communicating over the local/docker network
URLThe service's DNS name and port (e.g. the Docker Compose service name and its exposed port)

Click Save. This can be updated later if needed.

Path: Reusable Components > Posture Checks

Create two posture checks, one for WARP and one for Gateway:

  1. 1Click Add a check.
  2. 2Pick WARP from the list. The name is auto-filled. Save.
  3. 3Click Add a check again.
  4. 4Select Gateway. The name is auto-filled. Save.

Path: Access Controls > Policies

Three policies need to be created. Each is referenced by name in later steps.

FieldValue
Policy nameTeam Email Check
ActionAllow
Session duration12 hours
Rule typeSelectorValue
Include [OR]EmailsComma-separated list of authorised team emails

Leave all other settings as default and save.

FieldValue
Policy namePostureCheck
ActionAllow
Session durationSame as application session timeout
Rule typeSelectorValue
Include [OR]WARP-
Require [AND]Gateway-

Click +Add require to add the Gateway rule. Leave everything else default and save.

FieldValue
Policy nameWebhook Public Bypass
ActionBypass
Session durationSame as application session timeout
Rule typeSelectorValue
Include [OR]Everyone-

Leave everything else default and save.

Path: Access Controls > Applications

Two applications need to be created: one for the protected app, and one for public webhook paths.

Destinations: under Public Hostnames, add the same subdomain and domain configured in the tunnel step. Leave the path empty to protect all routes.

  • Allow access through browser-based RDP, SSH, or VNC sessions: OFF

Access Policies: add existing policy and select PostureCheck (Step 4, Policy 2).

Authentication settingValue
Accept all available identity providersOFF
Identity providerPick Google from the dropdown
Apply instant authenticationOFF
Authenticate with Cloudflare One ClientOFF (identity provider is Google)

Set the App name and Session duration to 6 hours. Save.

Before the how, the why: not every route in an app can sit behind interactive authentication. Webhook endpoints are called machine-to-machine by outside services (a payment provider, a Git host, an automation trigger) that cannot complete a browser login against your identity provider, so an auth challenge would silently break the integration. This second application exists to carve exactly those public routes out of Zero Trust enforcement while every other path on the same hostname stays protected. Keep the carve-out as narrow as possible and lean on the app's own safeguards for those routes, such as webhook signature verification or secret tokens in the URL.

Destinations: under Public Hostnames, use the same subdomain and domain. In the Path field, enter the webhook path that must remain publicly accessible without third-party authentication. For example, n8n exposes two paths: /webhook and /webhook-test.

Access Policies: add existing policy and select Webhook Public Bypass (Step 4, Policy 3).

  • Accept all available identity providers: ON (likely inconsequential for a Bypass policy)

Set a name and Session duration to 1 month. Save.

Path: Access Controls > Access Settings > Manage your App Launcher

Verify the following configuration is in place:

SettingExpected value
Assigned policyPostureCheck only
Login methodsGoogle only
Session duration15 minutes

Path: Team & Resources > Devices > Device Profiles

FieldValue
NameOnboarding Profile
DescriptionDevice profile for onboarding selected individuals
Expression selectorOperatorValue
User emailinComma-separated list of authorised emails

SettingValueNotes
Captive portal detectionON, 3 min timeoutAllows users to authenticate on hotel, airport, or other public Wi-Fi
Mode switchOFF
Device tunnel protocolWireGuard
Lock device client switchOFFTurn ON when employees are fully subsidised with company devices
Allow device to leave organisationONTurn OFF when employees are fully subsidised with company devices
Allow updatesON
Auto connectOFFTurn ON when employees are fully subsidised with company devices
Support URLYour support URLUse the small save button beside the field to save it separately
Service modeTraffic and DNS Mode
Local domain fallbackDefaultConfigure only if a local domain needs to be excluded from tunneling for local dev/testing

Select Exclude IPs and domains, then click Manage. Find the address 100.64.0.0/10 and delete it.

SettingValueNotes
Directly route Microsoft 365 trafficOFF
Allow users to enable local network exclusionON, 10 min timeoutLets users access local printers and similar devices
Device client interface IP DNS registrationON
SCCM VPN boundary supportON
NetBT (NetBIOS over TCP/IP)OFF

Save the profile.

Path: Devices > Management

  1. 01
    Open the policies

    Go to Device enrollment permissions > Manage > Policies.

  2. 02
    Attach the email policy

    Select existing policies and choose Team Email Check (Step 4, Policy 1). Save.

  3. 03
    Set the login method

    Switch to the Login methods tab, select Google, and save.

SettingValueNotes
Allow admin override codesOFFEnable only when an admin override scenario is needed
Install CA to system certificate storeONInstall available certificates to the certificate store of enrolled Windows, macOS, and Linux devices
Assign a unique IP address to each deviceONOverride the device's existing local interface IP with a unique IP address randomly assigned from the Carrier Grade NAT space (i.e. 100.64/10)

SettingValueNotes
Disconnect the Cloudflare One Client on all devicesOFFGlobal disconnection of client for the entire organization

SettingValueNotes
Allow all Cloudflare One traffic to reach enrolled devicesOFFAdvanced use case. Turn ON when needed and update configuration accordingly for better privacy

Path: Secure Web Gateway > Traffic Policies > Traffic Settings

SettingValueNotes
Allow Secure Web Gateway to proxy trafficON, UDP & ICMP
Inspect HTTPS requests with TLS decryptionOFFTurn ON when needed
Allow protocol detectionOFFTurn ON when needed and select required ports to scan

All of the following can be enabled as needed, leave OFF by default:

SettingDefault
Match extended email addressesOFF
Allow egress policy host selectorsOFF
Scan files for malwareOFF, enable upload/download file scanning as needed
Allow enhanced file detectionOFF

Set Log traffic activity to Capture All for all three categories.

The cloudflared client can be deployed in multiple ways. This guide covers the Docker method, specifically for self-managed systems like Coolify or AWS ECS (Elastic Container Service), where you control the Docker networks and containers yourself.

None of this is specific to Docker or Coolify either. Any internal service can be protected this way as long as a cloudflared client can be deployed in front of it, whether that is a bare metal VM, a Kubernetes cluster, or another container runtime. The Docker network example is what this guide walks through because it is the closest to a real production setup.

One tunnel token, one client per server
cloudflared can only resolve services on the Docker network it shares

Diagram: One tunnel token, one client per server.

  • Cloudflare Tunnel (one shared tunnel token)
  • cloudflared A (AWS VM)
  • cloudflared B (GCP VM)
  • Docker network A (apps on server A)
  • Docker network B (apps on server B)
  • cloudflared A same token to Cloudflare Tunnel
  • cloudflared B same token to Cloudflare Tunnel
  • cloudflared A shared network to Docker network A
  • cloudflared B shared network to Docker network B
  • cloudflared A cannot reach to Docker network B

To keep these manageable, deploy all cloudflared instances in a single dedicated Coolify project and follow a consistent naming convention: [ServerName_ServerModel].

  1. 01
    Create the client

    Create and assign the client to its server using the Coolify Cloudflared template (uses the latest image).

  2. 02
    Set the tunnel token

    Go to the Environment Variables section and put the token we copied in Step 2 as the value of CLOUDFLARE_TUNNEL_TOKEN and save.

  3. 03
    Remove host networking

    Edit the generated Docker Compose file: remove the network_mode: host entry from the cloudflared service.

Add the following inside the cloudflared service block:

docker-compose.yml (cloudflared service)yaml
networks:
  - coolify

Outside of the services block, add the external network declaration:

docker-compose.yml (top level)yaml
networks:
  coolify:
    external: true

Apply the same external network setup to the target app's Compose file (e.g. the n8n instance). This injects the cloudflared client into the shared Docker network, allowing it to resolve service names.

  • The service is protected behind the Cloudflare tunnel. Only enrolled users who have authenticated via the identity provider can access the app's subdomain. Unauthenticated requests are dropped.
  • Anyone without the Cloudflare One Client can still reach the team's App Launcher page, but attempting to use the identity provider will fail. The client being off triggers an error.
  • Anyone with the client installed and running but not enrolled will fail the IdP check, as their email is not on the allow-list.

Of the seven protection layers Cloudflare SASE offers, this setup exercises one fully (ZTNA) and one partially (SWG, through the WARP client and Gateway proxy settings in Section 9). That is a deliberate starting point rather than a limitation: once devices are enrolled and traffic flows through the edge, turning on TLS inspection, DLP, or malware scanning is a dashboard toggle away, not a new architecture. Start with ZTNA for the apps that must never be public, and grow into the rest of the stack as the need appears.

Keep the Conversation Going

Thoughts on this one?

If this sparked an idea, a disagreement, or a discussion, I would like to hear it.