Skip to content

WireGuard — sing-box

Endpoint, not outbound

WireGuard is configured as an endpoint in sing-box 1.11+, not as an outbound. The block sits under the root endpoints[] array with type: "wireguard", and is referenced from routing rules just like any named outbound.

Endpoint options

type: "wireguard" under endpoints[]:

FieldTypeDefaultAllowed valuesDescription
systemboolfalsetrue | falseUse the operating-system TUN device instead of the userspace gVisor stack. Higher throughput, but requires elevated privileges on most platforms.
namestring(auto)<string>Display name for the endpoint. Used in stats and the routing engine.
mtuuint321408<bytes>Tunnel MTU. The default is 1408 (12 bytes lower than Xray's 1420 because sing-box accounts for the IPv6 header overhead on the inner packet).
addressbadoption.Listable[netip.Prefix](required)[<CIDR>]Local tunnel addresses, list of `netip.Prefix`. At least one entry is required.
private_keystring(required)<base64 key>Local private key, 32 bytes base64-encoded.
listen_portuint160 (random)<port>UDP port used for outgoing WireGuard packets. 0 picks a random ephemeral port.
peers[]WireGuardPeer[][WireGuardPeer]Remote peers.
udp_timeoutbadoption.Duration5m<duration>Idle timeout for the underlying UDP session, used by gVisor's session table.
workersint(CPU-based)<int>Number of encryption-pipeline workers. 0 uses runtime.NumCPU().

Source: option/wireguard.go:9-20 · pinned at v1.13.11 (553cfa1)

The struct also embeds DialerOptions for the underlying UDP socket — bind_interface, routing_mark, detour, etc.

peers[]

FieldTypeDefaultAllowed valuesDescription
addressstring(unset)<host>Peer hostname or IP. Resolved at handshake time when a hostname is supplied.
portuint1651820<port>Peer UDP port.
public_keystring(required)<base64 key>Peer public key, 32 bytes base64-encoded.
pre_shared_keystring(unset)<base64 key>Optional pre-shared-key (32 bytes base64) for additional handshake mixing.
allowed_ipsbadoption.Listable[netip.Prefix][][<CIDR>]Source/destination CIDRs routed to this peer.
persistent_keepalive_intervaluint160<seconds>WireGuard persistent-keepalive interval. 0 disables keepalives.
reserved[]uint8(empty)<3 bytes>Three-byte WireGuard reserved-field override used by some commercial providers.

Source: option/wireguard.go:22-30 · pinned at v1.13.11 (553cfa1)

Examples

Single peer with system TUN:

json
{
  "endpoints": [
    {
      "type": "wireguard",
      "tag": "wg-ep",
      "system": true,
      "name": "wg0",
      "address": ["10.0.0.2/32", "fd00::2/128"],
      "private_key": "<base64-private-key>",
      "mtu": 1408,
      "peers": [
        {
          "address": "wg.example.com",
          "port": 51820,
          "public_key": "<base64-peer-public-key>",
          "allowed_ips": ["0.0.0.0/0", "::/0"],
          "persistent_keepalive_interval": 25
        }
      ]
    }
  ],
  "route": {
    "rules": [
      { "domain": ["geosite-private"], "outbound": "wg-ep" }
    ]
  }
}

Userspace device (no system TUN) for unprivileged runs:

json
{
  "endpoints": [
    {
      "type": "wireguard",
      "tag": "wg-userspace",
      "system": false,
      "address": ["172.16.0.2/24"],
      "private_key": "<base64>",
      "peers": [
        { "address": "1.2.3.4", "port": 51820, "public_key": "<base64>", "allowed_ips": ["0.0.0.0/0"] }
      ]
    }
  ]
}

Notes

  • WireGuard is always an endpoint in current sing-box. Pre-1.11 configs that used outbound: { type: wireguard } will fail to load — migrate to the endpoints model.
  • system: true uses the platform's TUN device directly. This is faster but requires root / Administrator. system: false (the default) uses gVisor's userspace TCP/IP stack — slower but unprivileged.
  • Keys must be base64 (32-byte raw, then base64). Hex keys (which Xray accepts) are not supported here.
  • The default MTU is 1408, not the wire-format 1420 — sing-box reserves 12 bytes for inner IPv6 header overhead.

Cross-core notes

  • Xray-core keeps WireGuard as a protocol-style outbound under outbounds[] with protocol: "wireguard". Accepts hex or base64 keys, defaults MTU to 1420. See WireGuard — Xray-core.
  • mihomo also keeps it as an outbound with a simplified single-peer form (top-level server/port/public-key/allowed-ips) and an optional amnezia-wg-option block. See WireGuard — mihomo.

Source: option/wireguard.go:9-30 · v1.13.11 (553cfa1)

Core Tutorial by Argsment