Cloudflare Zero Trust - Private Networks via WARP

I’ve finally got round to setting up all my machines to use Cloudflare “Zero Trust” ( It’s excellent! Apart from those machines now being protected from all external network access, I now have Cloudflare Access on everything and can connect via ssh (and setup a tunnel for other things like Remote Desktop). All built on WireGuard technology too, yay!. Connections appear smoother and snappier than before. The service is free for up-to 50 users in an “organisation” too. 😎

This doc records setting up my account’s Zero Trust organisation, allowing me to Connect through Cloudflare Access over SSH to devices in my organisation.

Setting up Zero Trust Access at Cloudflare

Follow Cloudflare’s getting started doc to enable your Zero Trust environment. Check off the items in that list, but be aware that the docs may not always tie-up with the current state of the apps or Cloudflare’s dashboard (you may need to hunt around for particular sections if they’ve moved to other / sub-sections for instance!). I’m not going to repeat their instructions here, however, as an aide-memoir for myself and to help out anyone else in their setups, the following may be useful. It details choices I made, as well as times I came across moved resources! All resource locations are obviously only correct at time of writing. The following numbered list corresponds to the list seen in the current getting started doc, but should still be useful if that resource changes.

  1. Login method: One-time PIN
  2. Now located at My Team > Groups. I currently have two groups set up:
    • “Admins” (set as default group): Include: Emails (A list of specified emails. NOTE: these can be outside any ‘chosen domain’)
    • “All Domain Users”: Include: Emails Ending In: (A list of domains (, currently just one - my ‘chosen domain’)
  3. Installing the Cloudflare certificate is only currently required if you’ll be intercepting traffic. However, I installed it on all my clients (iOS, macOS, Win) for which there are good installation instructions provided. If the cert isn’t installed and you enable traffic inspection, the Zero Trust client will scream a little, highlighting that the connection is no longer safe!
  4. Deploy WARP: I have access to all client devices so I chose “Manual deployment”.
  5. Log in to your organization’s Cloudflare Zero Trust (previously know as Teams as well) from each device. Users could do this themselves if they are ‘in’ your groups. Once completed, the regular client app switches to Zero Trust (with Warp). All being well, you should see each device listed in My Team > Devices
  6. Proxy is currently off, but when enabled, policies (groups of rules) are now located at Gateway > Policies
  7. Enable TLS decryption is currently off. Beware! Enabling this may break certain accesses that check for, or don’t play well with, proxies, such as Banking sites/apps etc. OK if you’re a proper organisation that is happy to not allow this kind of use, but not so handy if it’s just your family setup!

Add an ssh ‘application’ at Cloudflare

Setup a Group (if not already done)

Groups are helpful when you need to create multiple policies and apply them to a recurring set of users. Defining those users in a group speeds up your policy creation process.

To have a (pre)set group able to use ‘applications’ I created the following (I didn’t have this setup originally, so it’s now repeated here as an example)…

From the Zero Trust dashboard, select Access > Access Groups, select “Add a Group”

  • Group name: Admin
  • Default Group: Set as default group
  • Group configuration:

Create the app and add an access policy

Applications allow access to a resource in our organisation. The resource could be a SaaS, an internally hosted app (with Layer 4 managed access), or a self-hosted app that will simply take advantage of Cloudflare’s authoritative DNS. In this example we’re setting up ssh access for a particular machine (swap “machinename” below for the name or ID of your machine and “” for your domain).

From the Zero Trust dashboard, select Access > Applications.

  1. Click “Add an application”.
  2. Choose “Self-hosted” on the next page.
  3. Input a subdomain that will become the hostname where your “application” will be available to your users.
    • Application name: machinename SSH
    • Application domain:
  4. Click “Next”
  5. Add a policy. Name it something like “Access”
  6. Use ‘Assign a group’ to control who should have access to this app. Note that the policy must either have a group with an ‘Include type’ or have at least one ‘Include rule’ somewhere! I already have an Admin group setup as my default so that gets automatically checked 😎
  7. [OPTIONAL] Additional settings > Browser rendering: SSH
  8. Click ‘Add Application’ / ‘Save’

Setup the ‘app’ (using a tunnel) at the client

Cloudflare Tunnel creates a secure, outbound-only, connection to Cloudflare’s network. With an outbound-only model, you can prevent any direct access to this machine and lock down any externally exposed points of ingress. And with that, no open firewall ports.

Install cloudflared on the machine serving the app

Cloudflare Tunnel is made possible via a lightweight daemon from Cloudflare: cloudflared. For installation, see the Downloads page. The following instructions detail the process on a machine running mac OS (where I already have Homebrew installed).

brew install cloudflared

Login with cloudflared

Run the following command on the server to authenticate cloudflared to your Cloudflare account.

NOTE: If you are working on a machine that DOES NOT have a browser, or a browser window does not launch, simply copy the URL from the command-line output and visit the URL in a browser on any machine.

IMPORTANT: If you are working on a machine that DOES have a browser, ensure your default browser is already logged-in to Cloudflare FIRST so that the URL loads nicely!

cloudflared tunnel login

From the URL, choose your hostname from the presented list. Cloudflare will issue a certificate scoped to your account.

The resulting ~/.cloudflared/cert.pem file is used to authenticate the local instance of cloudflared.

You can now use cloudflared to control Cloudflare Tunnel connections in your Cloudflare account.

To check it’s working, try:

cloudflared tunnel list

Create a Tunnel

Cloudflare now allow tunnel management remotely, which is a huge win for setup. Navigate to the Cloudflare Dashboard > Access > Tunnels > “Create a tunnel”

  1. Name your tunnel. The name can be any value (however, maybe identify it as something like ‘cloudflared-tunnel-machinename’). Note a single Tunnel can also serve traffic for multiple hostnames to multiple services in your environment, including a mix of connection types like SSH and HTTP, however this example will use just one, which is set up shortly.
  2. Install (and run) a connector using the instruction for your environment i.e. for macOS it’s something like sudo cloudflared service install eyJhI...JMiJ9. If it sparks into life, you should see evidence in the “Connectors” pane of the “Create a tunnel” page.
  3. Lastly, add a configuration containing a dedicated DNS route e.g. for this example a subdomain something like machinename-ssh @ ( pointing to a Service such as SSH://localhost:22 is required.

Once setup, we should have a new DNS CNAME (machinename-ssh) pointing to our tunnel value of

To verify all is working, check the logs

tail -f /Library/Logs/com.cloudflare.cloudflared.err.log

We’d expect something resembling the following …

INF Starting tunnel tunnelID=ed67d574-b91d-447c-70ce-d911472b9ff7
INF Version 2022.7.1
INF GOOS: darwin, GOVersion: go1.18.3, GoArch: arm64
INF Generated Connector ID: 51fa7aab-f2ce-4a09-9643-7d9b2836a7d1
INF Initial protocol quic
INF Starting metrics server on
INF Connection 2ad19eb8-12de-48b0-a3ef-30ce32024e3d registered connIndex=0 location=AMS
INF Connection 63d2dfd3-ca40-7366-b9bc-2d1c94ca6370 registered connIndex=1 location=LHR
INF Connection 5c7a9c83-315f-4f1b-aa6c-e2493e9393e5 registered connIndex=2 location=AMS
INF Connection 130eb8f3-1b56-446c-9be9-9aa0afc8382c registered connIndex=3 location=LHR

The important part is that there are connections registered!

If you’re having trouble getting any, or more than one connection, AND you’re using Cloudflare WARP, you probably need to make an addition to WARP’s Split Tunnel settings (namely add the range - see the full list of Cloudflare IPs for reference). Once that range is added, you should see four healthy connections at all times.
If there are any issues, checkout the troubleshooting docs

Connect to app/machine via ssh

Using Native Terminal

  • Setup ssh config

    NOTE: cloudflared must be installed on the connecting machine (see above for installation)

    # discover location of cloudflared
    which cloudflared
    # -> /opt/homebrew/bin/cloudflared

    Add the following to the SSH configuration file ~/.ssh/config.

      ProxyCommand /opt/homebrew/bin/cloudflared access ssh --hostname %h
  • Connect via terminal

    You can now test the ssh flow by running a command to reach the service.

    # cloudflared will launch a browser window to prompt you to
    # authenticate before establishing the connection from your terminal

Using Browser-rendered terminal

Cloudflare can render an ssh client in your browser without the need for client software or end user configuration changes.

  • If not already enabled, Enable Browser Rendering:

    In the Zero Trust dashboard, navigate to Access > Applications. Select your app and click Edit > Settings tab > Additional settings:

    • Browser Rendering: SSH
    • SAVE!
  • Connect via browser

    In a browser, visit