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[]:
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
system | bool | false | true | false | Use the operating-system TUN device instead of the userspace gVisor stack. Higher throughput, but requires elevated privileges on most platforms. |
name | string | (auto) | <string> | Display name for the endpoint. Used in stats and the routing engine. |
mtu | uint32 | 1408 | <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). |
address | badoption.Listable[netip.Prefix] | (required) | [<CIDR>] | Local tunnel addresses, list of `netip.Prefix`. At least one entry is required. |
private_key | string | (required) | <base64 key> | Local private key, 32 bytes base64-encoded. |
listen_port | uint16 | 0 (random) | <port> | UDP port used for outgoing WireGuard packets. 0 picks a random ephemeral port. |
peers | []WireGuardPeer | [] | [WireGuardPeer] | Remote peers. |
udp_timeout | badoption.Duration | 5m | <duration> | Idle timeout for the underlying UDP session, used by gVisor's session table. |
workers | int | (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[]
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
address | string | (unset) | <host> | Peer hostname or IP. Resolved at handshake time when a hostname is supplied. |
port | uint16 | 51820 | <port> | Peer UDP port. |
public_key | string | (required) | <base64 key> | Peer public key, 32 bytes base64-encoded. |
pre_shared_key | string | (unset) | <base64 key> | Optional pre-shared-key (32 bytes base64) for additional handshake mixing. |
allowed_ips | badoption.Listable[netip.Prefix] | [] | [<CIDR>] | Source/destination CIDRs routed to this peer. |
persistent_keepalive_interval | uint16 | 0 | <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: trueuses 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[]withprotocol: "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 optionalamnezia-wg-optionblock. See WireGuard — mihomo.
Source: option/wireguard.go:9-30 · v1.13.11 (553cfa1)
