8 August 2026

Treating Cloudflare WARP Split Tunnels and Fallback Domains as Generated Configuration

When private sites and DNS exceptions multiply, WARP device-profile configuration becomes data. Source control can become the input and PowerShell the generator.


Client configuration is easy when there are five exceptions.

It becomes a platform problem when there are hundreds of sites, overlapping private networks, environment-specific DNS suffixes and several WARP profiles that all need to stay consistent.

At that scale, manually maintaining split-tunnel and fallback-domain entries is not configuration management. It is drift management.

Generated WARP client configuration

Start with one source of truth

The useful pattern is:

Reviewed site/application data

       Git

PowerShell generation
   ↙            ↘
DNS fallback   split tunnel
configuration  configuration

    WARP profiles

The input can be YAML, JSON or another structured format. The important requirement is that application/site information is maintained once.

From that source, automation can derive several Cloudflare configuration artefacts.

This is where WARP client profiles get interesting.

For a private name, two independent decisions may be required:

  1. Who should resolve this name?
  2. Should the resulting traffic traverse WARP?

Fallback domains answer the first question by choosing a resolver for a suffix.

Split tunnels answer the second by deciding whether matching IPs or domains are included in or excluded from the WARP path.

Treating these as unrelated spreadsheets is a good way to create hard-to-diagnose mismatches.

Generate both from the same object

Imagine a source entry like:

site: north-lab
private_suffix: onprem.north-lab.example
public_endpoint: vpn.north-lab.example

A generator can derive a fallback-domain object:

{
  "suffix": "onprem.north-lab.example",
  "dns_server": ["10.10.10.10"]
}

and a corresponding split-tunnel line or device-profile object.

The exact Cloudflare API representation can change. The architecture is more durable: derive related client policy from one reviewed input.

Base configuration plus generated configuration

Not every entry should be generated.

A practical model is:

base configuration
      +
generated site entries
      =
complete profile

The base file contains stable exceptions that apply everywhere. The generator adds the entries driven by the current site/application inventory.

That gives operators a clean distinction between intentional static policy and data-driven policy.

Make generation idempotent

Running the generator twice with unchanged input should produce the same output.

Avoid simply appending to the existing generated file. Instead:

  1. read the base file;
  2. build generated entries from source data;
  3. normalise and de-duplicate;
  4. write the complete output from scratch.

That one choice eliminates a surprising amount of configuration debris.

Validate before applying

Useful validation includes:

A generated file is not automatically a correct file.

Why source control helps

When the input is in Git, changes have context:

This converts what was previously client configuration into a small data pipeline.

The broader lesson

The more a Zero Trust deployment grows, the more configuration should be derived from authoritative data instead of copied between consoles.

Split tunnels and fallback domains are good examples because they sit at the boundary between DNS, routing and application ownership. Automating them reduces drift, but more importantly it gives those three domains a shared source of truth.


The examples are deliberately generic and do not expose private suffixes, DNS servers, repository locations or production WARP profiles.