← Back to library
Bypass Practice

WARP on the exit: connecting it

Why WARP on the exit — we covered that in the theory. Now let's set it up. I'll show how I connect a WARP outbound on a production node: credentials via wgcf, a wireguard outbound, routing rules for OpenAI/Spotify/Netflix, and the two traps everyone stumbles on — reserved and noKernelTun.

Read the theory

This material is about engineering your own infrastructure and is educational in nature. Complying with the laws of your own jurisdiction is on you.

Step 1: WARP credentials via wgcf

wgcf registers a free WARP account and issues a WireGuard profile (private key, v4/v6 addresses). The asset has a versioned name — there's no static link, so we pull the current one via the GitHub API:

get-wgcf.sh
WGCF_URL=$(curl -fsSL https://api.github.com/repos/ViRb3/wgcf/releases/latest \
  | grep -oE 'https://[^"]*wgcf_[0-9.]+_linux_amd64' | head -1)
curl -fsSL -o /usr/bin/wgcf "$WGCF_URL"
chmod +x /usr/bin/wgcf
wgcf register     # creates wgcf-account.toml (accept the ToS)
wgcf generate     # creates wgcf-profile.conf (PrivateKey, Address v4/v6)
cat wgcf-profile.conf

From wgcf-profile.conf we need PrivateKey and Address (v4/v6). From wgcf-account.toml we'll need client_idreserved is computed from it (more on that below).

Step 2: the wireguard outbound in the node config

Into the outbounds section of the config we add WARP. The comments say where to get what:

config.json
{
  "tag": "warp",
  "protocol": "wireguard",
  "settings": {
    "secretKey": "PRIVATE_KEY_X25519",
    "address": ["172.16.0.2/32", "2606:4700:110:XXXX/128"],
    "peers": [{
      "publicKey": "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=",
      "endpoint": "162.159.192.1:2408"
    }],
    "mtu": 1280,
    "reserved": [0, 0, 0],
    "noKernelTun": true
  }
}

Breakdown of the fields:

  • secretKeyPrivateKey from wgcf-profile.conf.
  • address — the v4/v6 Address from the profile. No IPv6 on the kernel — remove the v6 address, WARP will issue v6 itself.
  • the peer's publicKey — the Cloudflare WARP public key (a constant, as in the example).
  • endpoint — an explicit IPv4 162.159.192.1:2408. If you leave the domain name, it resolves to IPv6, and on a node without v6 WARP "hangs."
  • reserved — critical, see the traps.
  • noKernelTun: true — mandatory on a node in Docker.

Step 3: routing — what to send through WARP

Above the DIRECT/proxy rules we add: the domains of services that cut data centers → into warp. Everything else goes as it went:

config.json
{
  "type": "field",
  "outboundTag": "warp",
  "domain": [
    "geosite:openai",
    "domain:chatgpt.com",
    "domain:oaistatic.com",
    "domain:spotify.com",
    "domain:scdn.co",
    "geosite:netflix"
  ]
}

This way only what otherwise wouldn't work goes through WARP — the speed of the main traffic doesn't sag.

Trap 1: reserved (or the handshake hangs)

reserved is 3 bytes computed from your account's client_id. Without a correct reserved, the handshake to fresh WARP endpoints doesn't go through — the connection simply hangs. It's not directly in wgcf-profile.conf: get it via a "wgcf → Xray reserved" converter from the client_id/Reserved in wgcf-account.toml. Many panels compute it themselves — if you've set it and WARP hangs, recompute reserved first.

Trap 2: noKernelTun on a node in Docker

The top trap specifically on panel nodes. The symptom — WARP won't start, and in the node's logs:

node-log
failed to disable ipv4 rp_filter for all: open /proc/sys/net/ipv4/conf/all/rp_filter: read-only file system

The cause: the node's Xray runs in Docker, where /proc/sys is mounted read-only, while fresh Xray by default brings up WireGuard via kernel-TUN, which needs write access to /proc/sys. Cured by a single line "noKernelTun": true in the WARP outbound's settings — this is a return to the userspace stack, /proc/sys is no longer touched. After the change — restart the node, and the line Using kernel TUN should disappear from the log.

Step 4: verification

WARP isn't visible to the client and creates no Host — it's an internal node egress. We check it like this:

  • Connect with the client, open chat.openai.com — it should work.
  • On 2ip.ru see what your IP appears as: for OpenAI/Spotify it'll be Cloudflare, for everything else — your node.

If OpenAI came to life while the rest of the traffic still goes through the node — WARP is assembled correctly: a targeted white exit only for the problem services.

WARP+ (if you need speed)

Free WARP is rate-limited. There's a WARP+ license key — bind it and regenerate the profile:

warp-plus.sh
wgcf update --license-key YOUR_KEY
wgcf generate

For serious load — WARP+ or several WARP accounts with balancing between the warp outbounds.

Why all of this and what WARP solves and doesn't (geo, account, residency) — we covered in the paired theory "WARP on the exit: why and what it gives."

Next guide Zapret and unblocking YouTube → Article unclear or something off? Message me and I will help or fix it. @notrealvpn →
This material is educational and covers network-infrastructure engineering. You are responsible for complying with the laws of your jurisdiction.