Set up Cloudflare Mesh so your devices and servers can reach each other by private IP.
-
A Zero Trust organization with an active subscription, including the Free plan
-
A laptop or phone to connect as a client device
-
(Optional) A Linux server to deploy a Mesh node
Linux server requirements
OS version RHEL 9 1, RHEL 10, Debian 12, Debian 13, Fedora 43, Fedora 44, Ubuntu 22.04 LTS, Ubuntu 24.04 LTS, Ubuntu 26.04 LTS Processor AMD64 / x86-64 or ARM64 / AArch64 vCPU 3 minimum, 4 recommended RAM without a desktop 1 GB minimum, 2 GB recommended (for example, Ubuntu Server) RAM with a desktop 4 GB minimum, 8 GB recommended (for example, Ubuntu GNOME) Disk space 250 MiB minimum, 500 MiB recommended Network interface type Wi-Fi or LAN MTU 1381 bytes recommended 2 -
On RHEL 9 and later, enable the Extra Packages for Enterprise Linux (EPEL) ↗︎ repository (
sudo dnf install epel-release) before installingcloudflare-warp. EPEL provides dependencies required by the client UI. ↩ -
Minimum 1281 bytes with Path MTU Discovery ↩
-
Cloudflare Mesh requires that the Mesh node's device profile is configured to use MASQUE. Hostname routes, IPv6 CIDR routes, and high availability do not work if the device profile uses WireGuard instead.
Choose an enrollment method based on what you want to connect:
| Goal | Participant type | Enrollment method | Browser required |
|---|---|---|---|
| Run a service or route a subnet from Linux | Mesh node | Connector token | No |
| Connect an unattended Windows, macOS, or Linux device | Headless client device | Service token and managed deployment parameters | No |
| Connect a user device with identity | Client device | Interactive identity provider enrollment | Yes |
Choose the dashboard wizard or API and Terraform resources.
The setup wizard configures your account for Mesh networking and optionally guides you through creating a Mesh node. This is a one-time setup.
-
In the Cloudflare dashboard, go to Networking > Mesh.
Go to Mesh ↗ -
Select Add participant > Add node.
-
Enter a name for your node (for example,
web-serverorstaging-db). -
Select Create node.
-
Select Linux, Kubernetes, Docker Compose, or Docker CLI.
-
Follow the installation instructions for your selected method. The dashboard masks the node token but includes it when required by a copied command. Docker Compose configurations and Kubernetes manifests reference a secret instead of containing the token.
-
(Optional) If you are not ready to install the node, select I'll connect later. You can install the node from its detail page later.
-
If you installed the node, wait for it to connect and select Continue.
If you installed the node, it should appear as Online on the Mesh overview page along with its assigned Mesh IP. If the node does not come online, refer to Troubleshooting.
The dashboard wizard is not required. After account bootstrap, APIs and Terraform can automate the supported Mesh resources. You will need your account ID, Zero Trust team name, jq, and an API token with permissions for the resources you configure.
Before continuing, configure every item in Required account settings. The examples in this section configure the Mesh node device profile, node, and connector token. You must configure device enrollment and global settings separately. Allow all Cloudflare One traffic to reach enrolled devices and the ICMP Gateway proxy require dashboard configuration.
Before connecting a node, create a safe Include-mode profile. This request requires the Zero Trust Write permission. It matches Mesh nodes, uses MASQUE in Traffic and DNS mode, and routes only the Mesh IP range through Cloudflare:
set -euo pipefail
PROFILE_RESPONSE=$(
curl --fail-with-body --silent --show-error \
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/devices/policy" \
--request POST \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--header "Content-Type: application/json" \
--data "$(jq -n \
--arg match "identity.email == \"warp_connector@$TEAM_NAME.cloudflareaccess.com\"" \
'{
name: "Cloudflare Mesh nodes",
description: "Route Mesh IP traffic through Cloudflare",
enabled: true,
precedence: 100,
match: $match,
service_mode_v2: {mode: "warp"},
tunnel_protocol: "masque",
include: [{address: "100.96.0.0/12", description: "Cloudflare Mesh IPs"}]
}')"
)
jq -e '.success == true and (.result.id | type == "string")' \
<<< "$PROFILE_RESPONSE" > /dev/null
PROFILE_ID=$(jq -r '.result.id' <<< "$PROFILE_RESPONSE")Set ACCOUNT_ID, TEAM_NAME, and CLOUDFLARE_API_TOKEN in the shell before running the command. Use an unused precedence value that places this profile before broader profiles. Do not add an exclude field. A device profile cannot contain both include and exclude.
The API response uses the standard success, errors, messages, and result fields. A non-2xx response causes curl to fail. A response with success: false or without result.id causes jq to fail. Do not continue until the command returns zero and PROFILE_ID is set.
The following requests require an API token with either Cloudflare One Connectors Write or Cloudflare One Connector: WARP Write permission. To create a Mesh node and retrieve its connector token:
set -euo pipefail
NODE_RESPONSE=$(
curl --fail-with-body --silent --show-error \
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/warp_connector" \
--request POST \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--header "Content-Type: application/json" \
--data '{"name":"web-server"}'
)
jq -e '.success == true and (.result.id | type == "string")' \
<<< "$NODE_RESPONSE" > /dev/null
NODE_ID=$(jq -r '.result.id' <<< "$NODE_RESPONSE")
TOKEN_RESPONSE=$(
curl --fail-with-body --silent --show-error \
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/warp_connector/$NODE_ID/token" \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
)
MESH_NODE_TOKEN=$(jq -er \
'select(.success == true) | .result | select(type == "string" and length > 0)' \
<<< "$TOKEN_RESPONSE")The commands stop on an HTTP or API error. Do not continue until they return zero and set NODE_ID and MESH_NODE_TOKEN. If token retrieval fails after node creation, retry only the token request with the existing NODE_ID. Do not rerun the node creation request.
Install the node and replace <TOKEN> with the value of MESH_NODE_TOKEN:
IP forwarding is not required to reach the node by its Mesh IP. If the node will advertise CIDR routes, enable persistent forwarding before connecting it:
printf 'net.ipv4.ip_forward = 1\nnet.ipv6.conf.all.forwarding = 1\nnet.ipv6.conf.all.accept_ra = 2\n' | sudo tee /etc/sysctl.d/99-zzz-cloudflare-warp-connector.conf &&
sudo sysctl --systemcurl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor -o /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg &&
echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(. /etc/os-release && echo $VERSION_CODENAME) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list &&
sudo apt-get update -qq && sudo apt-get install -y -qq cloudflare-warpsudo warp-cli --accept-tos connector new <TOKEN> && sudo warp-cli --accept-tos connectOn RHEL 9 and later, enable the Extra Packages for Enterprise Linux (EPEL) repository before installing cloudflare-warp. EPEL provides dependencies required by the Cloudflare One Client UI:
sudo dnf install -y epel-releaseThen install the package:
curl -fsSl https://pkg.cloudflareclient.com/cloudflare-warp-ascii.repo | sudo tee /etc/yum.repos.d/cloudflare-warp.repo &&
sudo yum install -y cloudflare-warpsudo warp-cli --accept-tos connector new <TOKEN> && sudo warp-cli --accept-tos connectYou can also manage nodes with the cloudflare_zero_trust_tunnel_warp_connector ↗︎ resource. Use cloudflare_zero_trust_tunnel_warp_connector_config ↗︎ to manage node configuration.
Use the Add device workflow to find the Cloudflare One Client installer and organization name for a laptop or phone:
-
In the Cloudflare dashboard, go to Networking > Mesh.
Go to Mesh ↗ -
Select Add participant > Add device.
-
Select the device platform and use the provided link or QR code to install the Cloudflare One Client.
-
Open the client and select Cloudflare Zero Trust when prompted for a connection type.
-
Enter the organization name displayed in the Mesh dashboard and complete authentication.
The workflow does not enroll the device or verify connectivity. After the Cloudflare One Client displays Connected, test connectivity as described in Connect client devices.
From a Windows, macOS, or Linux client device, verify TCP connectivity to a Mesh node or another enrolled device. For example, test SSH:
nc -vz <MESH-IP> 22Test-NetConnection <MESH-IP> -Port 22Replace <MESH-IP> with the Mesh IP shown on the Mesh overview page. Replace port 22 with the port used by your service. You can test HTTP services from a mobile browser. A connected client or healthy connector status does not verify peer connectivity. Verify the application protocol you intend to use. If you turned on the ICMP Gateway proxy, you can also run ping <MESH-IP> as a diagnostic check.
Mesh traffic appears in Gateway network logs with Mesh as the Traffic Source when a Mesh node sends it, and as the Traffic Destination when it is routed to a Mesh node. Client device traffic appears under the enrolled user's identity.
For session-level detail, use Zero Trust Network Session Logs. Mesh sessions report OnrampType or Offramp as MESH, and DestinationReplicaID identifies which replica of a highly available node served the session.
The dashboard wizard configures the following Cloudflare One settings automatically for new deployments. Non-wizard deployments must configure the same settings:
| Setting | What it does |
|---|---|
| Device enrollment policy | Allows devices to enroll into your Cloudflare One account using email-based one-time PIN. Only created if you do not already have an existing device enrollment policy in your account. |
| Device profile | Creates a profile configured with Split Tunnels in Include mode, so only Mesh traffic routes through Cloudflare. This prevents disrupting existing network connectivity on your server. Only created if you do not already have an active Mesh node (formerly WARP Connector) in your account. |
| Allow all Cloudflare One traffic to reach enrolled devices and Assign a unique IP address to each device | Enables device-to-device connectivity for Mesh networking. |
| Gateway proxy | Enables TCP and UDP proxying for Mesh services. ICMP proxying is optional and supports diagnostics such as ping and traceroute. |
For automated deployments, the device profile documentation includes API and Terraform examples. Set service_mode_v2 = { mode = "warp" }, replace the generic example's wireguard protocol with tunnel_protocol = "masque", and configure Split Tunnels to route 100.96.0.0/12 through Cloudflare. Match Mesh nodes with identity.email == "warp_connector@<TEAM_NAME>.cloudflareaccess.com", and place this profile before broader profiles. The device enrollment documentation includes the Terraform enrollment-policy flow.
The cloudflare_zero_trust_device_settings ↗︎ resource supports unique device IPs and the TCP and UDP Gateway proxies:
resource "cloudflare_zero_trust_device_settings" "mesh" {
account_id = var.cloudflare_account_id
use_zt_virtual_ip = true
gateway_proxy_enabled = true
gateway_udp_proxy_enabled = true
}The Terraform resource does not configure Allow all Cloudflare One traffic to reach enrolled devices or the ICMP Gateway proxy. Before connecting participants, turn on enrolled-device reachability in the dashboard. Turn on ICMP only if you require ping, traceroute, or another ICMP-based workflow.
If your account already has a Cloudflare One deployment, the setup wizard will not overwrite your existing configuration. Verify the following settings are enabled for Mesh to work:
- Device enrollment — At least one enrollment rule must exist so that devices and nodes can register with your account.
- Device profile for Mesh nodes — Your Mesh nodes need a device profile that routes the Mesh IP range (
100.96.0.0/12) through Cloudflare. In Include mode, add the Mesh range. In Exclude mode, verify that no custom or legacy entry contains the Mesh range. - Mesh connectivity — In your device profile settings, enable Allow all Cloudflare One traffic to reach enrolled devices.
- Unique device IPs — Enable Assign a unique IP address to each device so that each participant gets a routable Mesh IP.
- Client mode — Mesh nodes must run in Traffic and DNS mode. DNS-only or proxy-only modes are not supported.
- Traffic proxying — Turn on the Gateway proxy for the protocols you use. TCP and UDP carry Mesh services. ICMP supports diagnostic tools such as
pingandtraceroute.
- Node shows as Offline — On the server, run
warp-cli status. If the output does not showStatus update: Connected:- Run
warp-cli connect. - If your private network uses a firewall to restrict Internet traffic, ensure that it allows the WARP ports and IPs.
- Review your WARP daemon logs for information about why the connection is failing.
- Run
- Client device cannot reach Mesh IPs — Verify that your Split Tunnel configuration routes the Mesh IP range (
100.96.0.0/12) through Cloudflare. For details, refer to Connect client devices. - Windows firewall blocks Mesh traffic — Windows Firewall blocks inbound traffic from
100.96.0.0/12by default. Add a firewall rule that allows incoming requests from this range for your desired protocols and ports.
For general client issues, refer to Troubleshoot the Cloudflare One Client.
- Connect client devices — Platform-specific installation details, Split Tunnel configuration, and firewall considerations.
- Run in Docker / Kubernetes — Deploy a Mesh node as a Docker container for Docker Compose, Kubernetes, and CI/CD pipelines.
- Add routes — Make an entire subnet behind your node reachable (databases, printers, other servers).
- Enable high availability — Run multiple replicas for production resilience.
- Tips and best practices — Cloud VPC configuration, updating the client, running alongside cloudflared.