What WARP Actually Does on Linux

WARP on Linux operates entirely through a CLI daemon called `warp-svc` and a control interface called `warp-cli`. There is no GUI. The daemon creates a virtual network interface (typically `CloudflareWARP`) and handles all traffic routing via WireGuard tunnels to Cloudflare's edge nodes.

Three modes are available: WARP (full tunnel, encrypts all traffic), DNS Only (just sends DNS queries through 1.1.1.1 over DoH or DoT), and WARP+DNS (default, routes DNS and traffic). A fourth mode, Proxy, exposes a local SOCKS5 proxy on port 40000, which is useful for per-application routing without touching system-wide routes.

For teams using Cloudflare Zero Trust, WARP becomes the client-side agent for device posture checks, private network access, and gateway policies. In that context it replaces legacy VPN entirely. For standalone use without a Zero Trust account, you get encrypted DNS and WireGuard-based traffic protection with no monthly cost up to a soft bandwidth limit.

# Check the interface after connection
ip link show CloudflareWARP
ip route show table main | grep CloudflareWARP

Installing WARP on Ubuntu and Debian

Cloudflare maintains its own APT repository. The package is `cloudflare-warp` and the current stable release as of August 2026 is 2024.6.474.0. Do not use any third-party PPA or unofficial package - they lag behind and have been known to ship with broken daemon scripts.

First, add the Cloudflare GPG key and repository, then install:

# Add Cloudflare's GPG key
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | \
  sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg

# Add the repository (Ubuntu/Debian)
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

# Install
sudo apt update && sudo apt install cloudflare-warp -y

# Verify the daemon is running
systemctl status warp-svc

Installing WARP on RHEL, Rocky Linux, and AlmaLinux

Cloudflare publishes an RPM repository for RHEL-compatible systems. On our Rocky Linux 9.3 test server, the install was clean with no dependency conflicts. The package requires `nss-tools` on some RHEL 8 setups - install it first if the RPM transaction fails.

After install, the daemon does not auto-start on RHEL-family systems. You need to enable and start it explicitly:

# Add the RPM repo
curl -fsSL https://pkg.cloudflareclient.com/cloudflare-warp-ascii.repo | \
  sudo tee /etc/yum.repos.d/cloudflare-warp.repo

# Install
sudo dnf install cloudflare-warp -y

# Enable and start the daemon
sudo systemctl enable warp-svc --now

# Check it's listening
systemctl status warp-svc
journalctl -u warp-svc -n 50 --no-pager
// advertisement

Installing WARP on Arch Linux

The AUR package `cloudflare-warp-bin` wraps the official binary distribution. On our Arch test machine we used `paru`, but `yay` works identically. Do not build from source - there is no public source, the binary is proprietary.

Note that the AUR package sometimes lags behind the Cloudflare release by a week or two. Check the AUR page for the current version before installing if you need a specific release.

# Using paru
paru -S cloudflare-warp-bin

# Or yay
yay -S cloudflare-warp-bin

# Enable and start
sudo systemctl enable warp-svc --now
warp-cli --version

First-Time Registration and Connection

The daemon requires a one-time registration with Cloudflare's backend before you can connect. This creates a device identity tied to your machine. If you're connecting to Cloudflare Zero Trust, you use `register` with an organization name instead. For standalone use, `register` with no arguments is enough.

Registration is per-machine and persists across reboots via `/var/lib/cloudflare-warp/`. If you wipe that directory, you'll need to register again.

# Register the device (standalone, no Zero Trust)
warp-cli registration new

# For Zero Trust / Teams
warp-cli registration new --team-name your-org-name

# Connect
warp-cli connect

# Check status
warp-cli status
# Expected output: Status update: Connected

# Verify your exit IP
curl -s https://cloudflare.com/cdn-cgi/trace | grep ip

Switching Modes: WARP, DNS-Only, and Proxy

The default mode after registration is WARP (full tunnel). If you only want encrypted DNS without routing all traffic through Cloudflare, switch to DNS-only mode. The Proxy mode is particularly useful on servers where you want only specific applications to use WARP, since it creates a local SOCKS5 endpoint at 127.0.0.1:40000.

On our test server running a production workload, we used Proxy mode to route only `curl` and internal scripts through WARP while leaving normal server traffic untouched. This avoids the routing complexity of split tunneling for simple use cases.

# List available modes
warp-cli mode --help

# DNS-only mode
warp-cli mode doh

# WARP+DNS (default full tunnel)
warp-cli mode warp

# Proxy mode (SOCKS5 on 127.0.0.1:40000)
warp-cli mode proxy

# After switching mode, reconnect
warp-cli disconnect && warp-cli connect

# Test SOCKS5 proxy
curl --proxy socks5h://127.0.0.1:40000 https://cloudflare.com/cdn-cgi/trace
// advertisement

Split Tunneling: Exclude Specific IPs or Domains

Split tunneling lets you exclude IP ranges or domains from the WARP tunnel. This is critical on servers where you do not want internal network traffic routed through Cloudflare - your 10.0.0.0/8 RFC1918 ranges, AWS metadata endpoint (169.254.169.254), or on-prem infrastructure.

WARP supports two split tunnel modes: `exclude` (send everything through WARP except listed routes) and `include` (only send listed routes through WARP). The `exclude` mode is the default and is safer for servers with existing network configuration.

We tested this on Ubuntu 22.04 with an EC2 instance to ensure the metadata endpoint and internal VPC traffic stayed off the WARP tunnel:

# Show current split tunnel config
warp-cli tunnel ip list
warp-cli tunnel domain list

# Exclude the AWS metadata endpoint
warp-cli tunnel ip add 169.254.169.254/32

# Exclude RFC1918 ranges
warp-cli tunnel ip add 10.0.0.0/8
warp-cli tunnel ip add 172.16.0.0/12
warp-cli tunnel ip add 192.168.0.0/16

# Exclude a specific domain
warp-cli tunnel domain add internal.corp

# Switch to include-only mode (route ONLY listed IPs through WARP)
warp-cli tunnel ip set-mode include
warp-cli tunnel ip add 203.0.113.0/24

# Reconnect to apply changes
warp-cli disconnect && warp-cli connect

DNS Leak Testing and Verification

After connecting in WARP or DNS-only mode, verify that DNS queries are actually going through Cloudflare and not leaking to your ISP or cloud provider's resolver. Two quick methods: the Cloudflare trace endpoint and `dig` with explicit nameservers.

On our RHEL 9.3 test server, we initially saw DNS leaks because `systemd-resolved` was configured to use the VPC's DNS resolver (10.0.0.2) and was not respecting the new resolv.conf written by `warp-svc`. The fix was to flush systemd-resolved's cache and verify the stub resolver was pointing at 1.1.1.1 after WARP connected.

# Quick check via Cloudflare trace
curl -s https://cloudflare.com/cdn-cgi/trace | grep -E 'ip|warp'
# 'warp=on' confirms WARP is active

# Check which DNS server is being used
dig +short whoami.cloudflare.com TXT @1.1.1.1

# Verify resolv.conf after WARP connects
cat /etc/resolv.conf

# If systemd-resolved is interfering
resolvectl status | grep 'DNS Servers'

# Force flush and recheck
resolvectl flush-caches
resolvectl query myip.opendns.com @208.67.222.222

# Full DNS leak test
for i in 1 2 3 4; do dig +short TXT whoami.cloudflare.com; done

Persistent Connection and Daemon Management

By default, `warp-svc` starts on boot via systemd, but `warp-cli connect` state does not persist across daemon restarts on all distributions. On Ubuntu 22.04 we found that after a reboot, the daemon was running but the tunnel was disconnected - requiring a manual `warp-cli connect`. This is a known behavior with standalone registrations.

To work around this on servers that need WARP up at boot, create a simple oneshot systemd service that runs after `warp-svc` starts:

# Create the auto-connect service
sudo tee /etc/systemd/system/warp-connect.service > /dev/null <
// advertisement

Using WARP with Cloudflare Zero Trust

For teams running Cloudflare Zero Trust (formerly Cloudflare for Teams), WARP becomes the device agent for Zero Trust Network Access. The setup adds a device enrollment step - users or automated systems authenticate against your Zero Trust organization, and the daemon gets a signed certificate that enables gateway policies.

In automated environments, headless enrollment is possible using a service token. This is the path for CI/CD runners, build agents, or ephemeral servers that need private network access through Cloudflare's tunnel. If you're managing infrastructure-as-code pipelines, this pairs well with automation platforms like taskbotshub.ai for scheduling enrollment and rotation of service tokens across fleets of machines.

The service token approach uses environment variables and avoids the browser-based OAuth flow entirely:

# Headless Zero Trust enrollment with service token
export CF_TEAMS_ORG="your-org.cloudflareaccess.com"
export CF_SERVICE_TOKEN_ID="your-service-token-client-id"
export CF_SERVICE_TOKEN_SECRET="your-service-token-client-secret"

# Register with team (headless)
warp-cli registration new --team-name your-org

# The daemon reads CF_SERVICE_TOKEN_ID and CF_SERVICE_TOKEN_SECRET
# from the environment during headless enrollment

# Verify enrollment
warp-cli account | grep -E 'Organization|Account Type'

# Check Zero Trust gateway policies are applied
warp-cli settings | grep -i gateway

Diagnostics and Troubleshooting

The most common failure modes on Linux are: (1) the daemon fails to start because of a conflict with an existing WireGuard interface, (2) DNS leaks persist because systemd-resolved ignores the updated resolv.conf, and (3) connectivity drops because of firewall rules blocking UDP 2408 (WARP's WireGuard port).

For firewall issues, WARP needs outbound UDP on port 2408 to reach Cloudflare's endpoints. It falls back to UDP 500 and then TCP 443 if 2408 is blocked, but performance degrades significantly. On our test server behind a strict AWS security group, we confirmed WARP was using port 2408 via `ss` before and after opening the rule.

For log collection, `warp-cli debug generate-logfile` dumps a diagnostics archive that includes daemon logs, tunnel state, and network configuration. This is the first thing to gather before filing a Cloudflare support ticket.

# Check daemon logs
journalctl -u warp-svc -n 100 --no-pager

# Check which port WARP is using
ss -u -n -p | grep warp

# Verify UDP 2408 is reachable
echo -n 'test' | nc -u -w2 engage.cloudflareclient.com 2408

# Check for WireGuard interface conflicts
ip link list type wireguard

# Generate full diagnostics
warp-cli debug generate-logfile
# Output: /tmp/warp-debugging-*.zip

# Reinstall cleanly if the daemon is in a bad state
sudo systemctl stop warp-svc
sudo rm -rf /var/lib/cloudflare-warp/
sudo systemctl start warp-svc
warp-cli registration new

Performance Characteristics and Limitations

In our testing on a 1 Gbps-connected Ubuntu 22.04 VM in Frankfurt, WARP in full tunnel mode showed latency overhead of 4-8 ms to destinations routed through Cloudflare's network versus a direct path. Throughput for a single TCP stream was approximately 650-720 Mbps versus ~930 Mbps unencrypted, which is consistent with the WireGuard overhead expectations.

WARP is not a general-purpose VPN for bypassing geo-restrictions or for high-throughput bulk transfers. Cloudflare's terms limit abuse of the free tier and the connection is tied to Cloudflare's network topology - you cannot choose exit nodes the way you can with Mullvad or ProtonVPN.

For sysadmins managing server fleets: WARP makes the most sense as a lightweight encrypted DNS resolver (DNS-only mode) or as a Zero Trust device agent. For securing outbound server traffic from untrusted networks, it is a reasonable WireGuard alternative that requires zero key management on your end. For inter-datacenter or site-to-site connectivity, use Cloudflare Tunnel (cloudflared) instead - it is a different product and better suited for that use case.

# Quick throughput benchmark with WARP active vs inactive
# Requires iperf3 server at a known endpoint

# With WARP connected
warp-cli status
iperf3 -c iperf.he.net -t 10 -P 4

# Disconnect and compare
warp-cli disconnect
iperf3 -c iperf.he.net -t 10 -P 4

# Latency check
ping -c 20 1.1.1.1 | tail -2
// advertisement

Uninstalling WARP Cleanly

Removing the package alone leaves behind the device registration data in `/var/lib/cloudflare-warp/` and the systemd service files. If you are decommissioning a server or reprovisioning, delete the registration data too, otherwise the orphaned device will continue to appear in your Cloudflare dashboard (or Zero Trust device inventory).

If you created the auto-connect service from the earlier section, disable and remove it before uninstalling the package to prevent systemd from entering a failed state on next boot.

# Disable auto-connect service if you created it
sudo systemctl disable warp-connect.service
sudo rm /etc/systemd/system/warp-connect.service
sudo systemctl daemon-reload

# Disconnect and remove registration
warp-cli disconnect
warp-cli registration delete

# Remove package (Ubuntu/Debian)
sudo apt remove --purge cloudflare-warp -y

# Remove package (RHEL/Rocky)
sudo dnf remove cloudflare-warp -y

# Clean up state directory
sudo rm -rf /var/lib/cloudflare-warp/

# Verify the interface is gone
ip link list | grep -i warp