---
title: Deploy WARP on headless Linux machines · Cloudflare One docs
description: This tutorial explains how to deploy the Cloudflare WARP client on
  headless Linux devices using a service token and an installation script.
lastUpdated: 2025-11-20T23:13:05.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/cloudflare-one/tutorials/warp-on-headless-linux/
  md: https://developers.cloudflare.com/cloudflare-one/tutorials/warp-on-headless-linux/index.md
---

This tutorial explains how to deploy the [Cloudflare WARP client](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/warp/) 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](https://developers.cloudflare.com/cloudflare-one/traffic-policies/identity-selectors/) and logging will be unavailable.

Note

This tutorial focuses on deploying WARP as an endpoint device agent. If you are looking to deploy WARP as a gateway to a private network, refer to the [WARP Connector documentation](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/warp-connector/).

## Prerequisites

* [Cloudflare Zero Trust account](https://developers.cloudflare.com/cloudflare-one/setup/#create-a-zero-trust-organization)

## 1. Create a service token

Fully automated deployments rely on a service token to enroll the WARP 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](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/warp/configure-warp/device-profiles/).

To create a service token:

* Dashboard

  1. In [Cloudflare One](https://one.dash.cloudflare.com), go to **Access controls** > **Service credentials** > **Service Tokens**.

  2. Select **Create Service Token**.

  3. 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.

  4. Choose a **Service Token Duration**. This sets the expiration date for the token.

  5. Select **Generate token**. You will see the generated Client ID and Client Secret for the service token, as well as their respective request headers.

  6. Copy the Client Secret.

     Warning

     This is the only time Cloudflare Access will display the Client Secret. If you lose the Client Secret, you must generate a new service token.

* API

  1. Make a `POST` request to the [Access Service Tokens](https://developers.cloudflare.com/api/resources/zero_trust/subresources/access/subresources/service_tokens/methods/create/) endpoint:

     Required API token permissions

     At least one of the following [token permissions](https://developers.cloudflare.com/fundamentals/api/reference/permissions/) is required:

     * `Access: Service Tokens Write`

     ```bash
     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"
       }'
     ```

  2. Copy the `client_id` and `client_secret` values returned in the response.

     ```json
     "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
     }
     ```

     Warning

     This is the only time Cloudflare Access will display the Client Secret. If you lose the Client Secret, you must generate a new service token.

* Terraform (v5)

  1. Add the following permission to your [`cloudflare_api_token`](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/api_token):

     * `Access: Service Tokens Write`

  2. Configure the [`cloudflare_zero_trust_access_service_token`](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/zero_trust_access_service_token) resource:

     ```tf
     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
       }
     }
     ```

  3. Get the Client ID and Client Secret of the service token:

     Example: Output to CLI

     1. Output the Client ID and Client Secret to the Terraform state file:

        ```tf
        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
        }
        ```

     2. Apply the configuration:

        ```sh
        terraform apply
        ```

     3. Read the Client ID and Client Secret:

        ```sh
        terraform output -raw example_service_token_client_id
        ```

        ```sh
        terraform output -raw example_service_token_client_secret
        ```

     Example: Store in HashiCorp Vault

     ```tf
       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
         })
       }
     ```

## 2. Configure device enrollment permissions

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:

1. In [Cloudflare One](https://one.dash.cloudflare.com), go to **Team & Resources** > **Devices**. Select the **Management** tab.

2. In **Device enrollment permissions**, select **Manage**.

3. In the **Policies** tab, select **Create new policy**. A new tab will open with the policy creation page.

4. For **Action**, select *Service Auth*.

5. 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>` |

6. Save the policy.

7. Go back to **Device enrollment permissions** and add the newly created policy to your permissions.

8. Select **Save**.

## 3. Create an installation script

You can use a shell script to automate WARP installation and registration. The following example shows how to deploy WARP on Ubuntu 24.04.

1. In a terminal, create a new `.sh` file using a text editor. For example:

   ```sh
   vim install_warp.sh
   ```

2. Press `i` to enter insert mode and add the following lines:

   ```bash
   #!/bin/bash
   set -e


   # Download and install the WARP 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 WARP deployment parameters
   function mdm() {
     sudo touch /var/lib/cloudflare-warp/mdm.xml
     cat > /var/lib/cloudflare-warp/mdm.xml << "EOF"
   <dict>
       <key>auth_client_id</key>
       <string>88bf3b6d86161464f6509f7219099e57.access</string>
       <key>auth_client_secret</key>
       <string>bdd31cbc4dec990953e39163fbbb194c93313ca9f0a6e420346af9d326b1d2a5</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
   ```

3. If you are using Debian or RHEL / CentOS, modify the `warp()` function so that it installs the correct [WARP package](https://pkg.cloudflareclient.com/) for your OS.

4. Modify the values in the `mdm()` function:

   1. For `auth_client_id` and `auth_client_secret`, replace the string values with the Client ID and Client Secret of your [service token](https://developers.cloudflare.com/cloudflare-one/tutorials/warp-on-headless-linux/#1-create-a-service-token).
   2. For `organization`, replace `your-team-name` with your Zero Trust team name.
   3. (Optional) Add or modify other [WARP deployment parameters](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/warp/deployment/mdm-deployment/parameters/) according to your preferences.

5. Press `esc`, then type `:x` and press `Enter` to save and exit.

## 4. Install WARP

To install WARP using the example script:

1. Make the script executable:

   ```sh
   chmod +x install_warp.sh
   ```

2. Run the script:

   ```sh
   sudo ./install_warp.sh
   ```

WARP is now deployed with the configuration parameters stored in `/var/lib/cloudflare-warp/mdm.xml`. Assuming [`auto_connect`](https://developers.cloudflare.com/cloudflare-one/team-and-resources/devices/warp/deployment/mdm-deployment/parameters/#auto_connect) is configured, WARP will automatically connect to your Zero Trust organization. Once connected, the device will appear in [Cloudflare One](https://one.dash.cloudflare.com) under **Team & Resources** > **Devices** with the email `non_identity@<team-name>.cloudflareaccess.com`.
