← Back to articles

// TECHNICAL GUIDE

Migrating from WireGuard to Cloudflare Zero Trust (WARP)

This tutorial guides through the migration of a private network connection based on WireGuard to Cloudflare Zero Trust (WARP), with the goal of eliminating port exposure and improving internal network security. The migration is carried out in stages, ensuring that remote access remains functional throughout the process.

2026-09-298 min readLeer en español ↗
Infraestructura

Introduction

This tutorial guides through the migration of a private network connection based on WireGuard to Cloudflare Zero Trust (WARP), with the goal of eliminating port exposure and improving internal network security. The migration is carried out in stages, ensuring that remote access remains functional throughout the process.

Objective

Replace a private network connection based on WireGuard with an incoming port exposed by remote access via Cloudflare Zero Trust, eliminating all open ports toward the internal network.

Architecture

The proposed architecture eliminates the dependency on an exposed UDP port and a DDNS service. Instead, it uses an outgoing tunnel initiated by cloudflared on an internal host, connecting directly to the internal network from the Cloudflare network.

Prerequisites

Step-by-Step Procedure

Phase 0 — Prerequisites

  1. Break the credential circular dependency: Export 2FA recovery codes to offline support, verify that the recovery email does not depend on internal infrastructure, and save a copy of the WireGuard configuration file of a peer outside the infrastructure.

  2. Pre-cleaning: Review WireGuard peers and remove those that are not used.

  3. Decisions: Select a neutral hostname, choose the authentication method, define the split tunnel mode, and decide whether to migrate streaming services.

Phase 1 — Zero Trust Tenant

  1. In the Cloudflare dashboard, go to Zero Trust and create the organization.

  2. Choose the team name. This generates <team-name>.cloudflareaccess.com, which is public.

  3. Select the Free plan (up to 50 users).

  4. Note the device domain — it is needed on each client.

Phase 2 — Connector cloudflared

  1. Create the tunnel: In the Networks → Tunnels section, create a tunnel with Cloudflared and copy the token.

  2. Host settings: Configure network parameters to avoid throughput and ICMP issues.

  3. Deploy: Use a docker-compose.yml to deploy the connector with the token and verify the logs.

Phase 3 — Private Routes

  1. In the Networks → Routes section, add CIDR routes for each internal network to reach.

  2. Verify that each route points to the correct tunnel.

Phase 4 — Device Profile

  1. In Device and Resources → Devices → Device Profiles, configure the service mode, tunnel protocol, split tunnel in Include mode, and Local Domain Fallback.

  2. Do not touch options such as direct routing for Microsoft 365 or installing CA in the system store.

Phase 5 — Clients

  1. Android: Install the client from the store, log in with the team name, and verify the kill switch.

  2. Windows: Download the client from the tenant, install it, log in, and verify connectivity.

  3. Linux: Install the client from official repositories, log in, and verify connectivity with commands such as ping, ssh, and dig.

Validation

Cut

Rollback

Limitations

Decision or Verification Table

Decision Recommendation
Team name Something neutral; do not include sensitive information
Authentication method One-time PIN via email to start
Split tunnel Include mode with only internal CIDRs
Client protocol WireGuard (more mature than MASQUE)
Streaming services Do not migrate — see §9

Code Blocks

sudo tee /etc/sysctl.d/98-quic-buffers.conf > /dev/null << 'EOF'
net.core.rmem_max = 7500000
net.core.wmem_max = 7500000
EOF
echo 'net.ipv4.ping_group_range = 0 2147483647' | sudo tee /etc/sysctl.d/99-cloudflared-icmp.conf
sudo sysctl --system
services:
  cloudflared-warp:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared-warp
    restart: unless-stopped
    network_mode: host
    command: tunnel --no-autoupdate run --token ${TUNNEL_TOKEN}
    env_file: .env

Warnings

Warning: The enrollment link token expires in 60 seconds. Copying it, pasting it, and executing it manually almost always fails due to expiration. If the flow is delayed, regenerate it:

warp-cli registration delete
warp-cli registration new <team-name>

Warning: If the primary DNS resolver lives in the hypervisor, point the fallback to a secondary resolver that lives on the same host as the connector. This way, internal names continue resolving when the hypervisor is down — which is precisely when access is needed the most.