Skip to content

WireGuard — Xray-core

Xray-core has a userspace WireGuard implementation that runs as a protocol on both sides. On Linux, an optional kernel-TUN fast path is available — set noKernelTun: true to opt back into the userspace wireguard-go device.

Settings

settings for an outbound or inbound of "protocol": "wireguard":

FieldTypeDefaultAllowed valuesDescription
noKernelTunboolfalsetrue | falseDisable the kernel-TUN fast path (Linux only) and run the userspace wireguard-go device instead. Useful for unprivileged runs.
secretKeystring(required)<key>Local private key. Accepts hex (64 chars), base64 (padded or padless), or URL-safe base64 — see ParseWireGuardKey at infra/conf/wireguard.go:126.
address[]string[10.0.0.1, fd59:...:0001][<CIDR or IP>]Local interface address(es). If omitted, two bogon IPs are used (one IPv4, one IPv6).
peers[]*WireGuardPeerConfig[][WireGuardPeerConfig]Remote peers. For the standard single-peer setup this is a one-element list.
mtuint321420<bytes>Tunnel MTU. 0 substitutes 1420 (the WireGuard wire-format default).
workersint320 (CPU-based)<int>Number of worker goroutines for the encryption pipeline. 0 uses runtime.NumCPU().
reserved[]byte(empty)<3 bytes>Three-byte reserved-field override (used by some commercial WG implementations). Must be empty or exactly 3 bytes.
domainStrategystringforceipforceip | forceipv4 | forceipv6 | forceipv4v6 | forceipv6v4How peer endpoint hostnames are resolved. The four-letter forms control which family is tried first (v4v6 = IPv4 then IPv6 fallback).

Source: infra/conf/wireguard.go:51-62 · pinned at v26.6.1 (94ffd50)

peers[]

FieldTypeDefaultAllowed valuesDescription
publicKeystring(required)<key>Peer public key. Accepts the same formats as `secretKey`.
preSharedKeystring(unset)<key>Optional PSK for additional handshake security.
endpointstring(required for outbound)<host:port>Where to reach the peer. Hostname is allowed and re-resolved at handshake time.
keepAliveuint320<seconds>WireGuard persistent-keepalive interval. 0 disables keepalives.
allowedIPs[]string["0.0.0.0/0", "::0/0"][<CIDR>]Source/destination CIDRs routed to this peer. Defaults to all-routes-on if omitted.

Source: infra/conf/wireguard.go:13-19 · pinned at v26.6.1 (94ffd50)

Examples

Outbound to a single WireGuard peer:

json
{
  "outbounds": [
    {
      "tag": "wg-out",
      "protocol": "wireguard",
      "settings": {
        "secretKey": "<base64-private-key>",
        "address": ["10.0.0.2/32", "fd00:dead:beef::2/128"],
        "mtu": 1420,
        "peers": [
          {
            "publicKey": "<base64-peer-public-key>",
            "endpoint": "wg.example.com:51820",
            "allowedIPs": ["0.0.0.0/0", "::/0"],
            "keepAlive": 25
          }
        ],
        "domainStrategy": "forceipv4v6"
      }
    }
  ]
}

Outbound with a 3-byte reserved field (some commercial providers):

json
{
  "outbounds": [
    {
      "tag": "wg-cloak",
      "protocol": "wireguard",
      "settings": {
        "secretKey": "<base64>",
        "address": ["172.16.0.2/32"],
        "reserved": [123, 45, 67],
        "peers": [
          { "publicKey": "<base64>", "endpoint": "engage.cloudflareclient.com:2408" }
        ]
      }
    }
  ]
}

Notes

  • Keys are normalized to hex internally. Hex (64 hex chars), padded base64, and URL-safe base64 are all accepted on input (infra/conf/wireguard.go:133-148).
  • address defaults to bogon IPs if omitted, which works for outbound- only setups but breaks any traffic that uses the WireGuard interface for its source address. Set this explicitly for any non-trivial configuration.
  • mtu: 0 is silently rewritten to 1420 at build time (infra/conf/wireguard.go:91-95).
  • reserved must be empty or exactly 3 bytes. A length-2 or length-4 array fails to build (infra/conf/wireguard.go:100-102).
  • The noKernelTun flag is the only way to opt out of the kernel-TUN fast path on Linux. Other platforms always use userspace wireguard-go.

Cross-core notes

  • sing-box moved WireGuard to the endpoints model in 1.11+ — see WireGuard — sing-box for the new field shapes (private_key, address, peers[], udp_timeout).
  • mihomo accepts a simplified single-peer form (top-level server/port/public-key/allowed-ips) or a verbose peers: list, and exposes an amnezia-wg-option block for AmneziaWG compatibility. See WireGuard — mihomo.

Source: infra/conf/wireguard.go:13-62 · v26.6.1 (94ffd50)

Core Tutorial by Argsment