This tutorial explains how to deploy the Cloudflare One Client on Linux devices using a service token and an installation script. This deployment workflow is designed for headless servers - that is, servers which do not have access to a browser for identity provider logins - and for situations where you want to fully automate the onboarding process. Because devices will not register through an identity provider, identity-based policies and logging will be unavailable.
- Cloudflare Zero Trust account
- Root or
sudoaccess on a supported Linux device - Zero Trust team name
- Service token Client ID and Client Secret
Fully automated deployments rely on a service token to enroll the Cloudflare One Client in your Zero Trust organization. You can use the same token to enroll multiple devices, or generate a unique token per device if they require different device profile settings.
To create a service token:
-
In the Cloudflare dashboard ↗︎, go to Zero Trust > Access controls > Service credentials > Service Tokens.
-
Select Create Service Token.
-
Name the service token. The name allows you to easily identify events related to the token in the logs and to revoke the token individually.
-
Choose a Service Token Duration. This sets the expiration date for the token.
-
Select Generate token. You will see the generated Client ID and Client Secret for the service token, as well as their respective request headers.
-
Copy the Client Secret.
-
Make a
POSTrequest to the Access Service Tokens endpoint:
At least one of the following token permissions is required:Required API token permissions
Access: Service Tokens Write
Create a service tokenbash curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/service_tokens" \ --request POST \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --json '{ "name": "CI/CD token", "duration": "8760h" }' -
Copy the
client_idandclient_secretvalues returned in the response.Responsejson "result": { "client_id": "88bf3b6d86161464f6509f7219099e57.access", "client_secret": "bdd31cbc4dec990953e39163fbbb194c93313ca9f0a6e420346af9d326b1d2a5", "created_at": "2025-09-25T22:26:26Z", "expires_at": "2026-09-25T22:26:26Z", "id": "3537a672-e4d8-4d89-aab9-26cb622918a1", "name": "CI/CD token", "updated_at": "2025-09-25T22:26:26Z", "duration": "8760h", "client_secret_version": 1 }
-
Add the following permission to your
cloudflare_api_token↗︎:Access: Service Tokens Write
-
Configure the
cloudflare_zero_trust_access_service_token↗︎ resource:resource "cloudflare_zero_trust_access_service_token" "example_service_token" { account_id = var.cloudflare_account_id name = "Example service token" duration = "8760h" lifecycle { create_before_destroy = true } } -
Get the Client ID and Client Secret of the service token:
Example: Output to CLI
- Output the Client ID and Client Secret to the Terraform state file:
output "example_service_token_client_id" { value = cloudflare_zero_trust_access_service_token.example_service_token.client_id } output "example_service_token_client_secret" { value = cloudflare_zero_trust_access_service_token.example_service_token.client_secret sensitive = true } - Apply the configuration:
terraform apply - Read the Client ID and Client Secret:
terraform output -raw example_service_token_client_idterraform output -raw example_service_token_client_secret
Example: Store in HashiCorp Vault
resource "vault_generic_secret" "example_service_token" { path = "kv/cloudflare/example_service_token" data_json = jsonencode({ "CLIENT_ID" = cloudflare_access_service_token.example_service_token.client_id "CLIENT_SECRET" = cloudflare_access_service_token.example_service_token.client_secret }) } - Output the Client ID and Client Secret to the Terraform state file:
Device enrollment permissions determine the users and devices that can register WARP with your Zero Trust organization.
To allow devices to enroll using a service token:
-
In the Cloudflare dashboard ↗︎, go to Zero Trust > Team & Resources > Devices. Select the Management tab.
-
In Device enrollment permissions, select Manage.
-
In the Policies tab, select Create new policy. A new tab will open with the policy creation page.
-
For Action, select Service Auth.
-
For the Selector field, you have two options: you can either allow all service tokens (
Any Access Service Token) or specific service tokens (Service Token). For example:Rule Action Rule type Selector Value Service Auth Include Service Token <TOKEN-NAME> -
Save the policy.
-
Go back to Device enrollment permissions and add the newly created policy to your permissions.
-
Select Save.
To configure service-token enrollment with Terraform, refer to Check for a service token.
You can use a shell script to automate WARP installation and registration. The following example shows how to deploy the Cloudflare One Client on Ubuntu 24.04.
-
In a terminal, create a new
.shfile using a text editor. For example:umask 077 vim install_warp.sh -
Press
ito enter insert mode and add the following lines:#!/bin/bash set -e # Download and install the Cloudflare One Client function warp() { curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list sudo apt-get update --assume-yes sudo apt-get install --assume-yes cloudflare-warp } # Create an MDM file with your Cloudflare One Client deployment parameters function mdm() { sudo install -m 600 /dev/null /var/lib/cloudflare-warp/mdm.xml sudo tee /var/lib/cloudflare-warp/mdm.xml > /dev/null << "EOF" <dict> <key>auth_client_id</key> <string>YOUR_CLIENT_ID</string> <key>auth_client_secret</key> <string>YOUR_CLIENT_SECRET</string> <key>auto_connect</key> <integer>1</integer> <key>onboarding</key> <false/> <key>organization</key> <string>your-team-name</string> <key>service_mode</key> <string>warp</string> </dict> EOF } #main program warp mdm sudo systemctl restart warp-svc -
If you are using Debian or RHEL / CentOS, modify the
warp()function so that it installs the correct WARP package ↗︎ for your OS. -
Modify the values in the
mdm()function:- For
auth_client_idandauth_client_secret, replace the string values with the Client ID and Client Secret of your service token. - For
organization, replaceyour-team-namewith your Zero Trust team name. - (Optional) Add or modify other Cloudflare One Client deployment parameters according to your preferences.
- For
-
Press
esc, then type:xand pressEnterto save and exit.
To install the Cloudflare One Client using the example script:
-
Make the script executable:
chmod 700 install_warp.sh -
Run the script:
sudo ./install_warp.sh -
Delete the script because it contains the service token secret:
rm install_warp.sh
The Cloudflare One Client is now deployed with the configuration parameters stored in the root-only /var/lib/cloudflare-warp/mdm.xml. Assuming auto_connect is configured, the Cloudflare One Client will automatically connect to your Zero Trust organization.
Verify registration and connection:
sudo warp-cli --accept-tos registration show
sudo warp-cli --accept-tos statusSuccessful enrollment creates a device in Zero Trust > Team & Resources > Devices with the email non_identity@<team-name>.cloudflareaccess.com. Verify that status reports Connected. A command completion or HTTP redirect alone does not prove registration or connectivity.
The registration and status commands verify enrollment and the connection to Cloudflare. To verify end-to-end traffic, connect to an included destination using the protocol you intend to use. For Cloudflare Mesh, follow Verify connectivity.
If the client reports Registration Missing due to: Does not exist in API, or the warp-svc logs show an HTTP 400 enrollment response, enrollment failed. Confirm that the service token policy uses the Service Auth action, the policy is attached to device enrollment permissions, and the MDM team name and token values are correct. After correcting or confirming the configuration, restart the service and repeat both verification commands:
sudo systemctl restart warp-svc
sudo warp-cli --accept-tos registration show
sudo warp-cli --accept-tos status