Skip to content

Transport — sing-box ​

sing-box's transport options live in the transport block embedded on every TLS-capable inbound and outbound. The block is polymorphic: the type field selects one of five transport variants, and the matching subset of fields applies.

json
"transport": { "type": "<ws|http|grpc|quic|httpupgrade>", ...variant fields }

type: "ws" ​

FieldTypeDefaultAllowed valuesDescription
pathstring//<path>WebSocket path.
headersbadoption.HTTPHeader{}{<header>: <value or list>}Extra upgrade-request headers.
max_early_datauint320<bytes>Maximum bytes of 0-RTT early data buffered before the WS handshake completes. 0 disables.
early_data_header_namestringSec-WebSocket-Protocol<header name>HTTP header carrying base64-encoded early data when the server expects it under a non-standard name.

Source: option/v2ray_transport.go:94-99 · pinned at v1.14.2 (af6e64c)

type: "http" (HTTP/2) ​

FieldTypeDefaultAllowed valuesDescription
hostbadoption.Listable[string][][<hostname>]List of Host header values. Server uses the list for SNI matching; client picks one randomly per request.
pathstring//<path>HTTP path.
methodstringPUT<HTTP method>HTTP method. Standard transport uses PUT to discourage caches.
headersbadoption.HTTPHeader{}{<header>: <value or list>}Extra request headers.
idle_timeoutbadoption.Duration0<duration>Server: close HTTP/2 clients that stay idle this long (GOAWAY). Client: send a health-check PING after this long without received frames. 0 disables both.
ping_timeoutbadoption.Duration15s<duration>HTTP/2 client: how long to wait for a PING response before closing the connection. 0 means the 15s default; PINGs are only sent when idle_timeout is set.

Source: option/v2ray_transport.go:85-92 · pinned at v1.14.2 (af6e64c)

The HTTP transport uses HTTP/2 when the surrounding TLS block is enabled; TLS is not enforced, and without it the transport falls back to plain HTTP/1.1. There is no HTTP/3 mode.

type: "grpc" ​

FieldTypeDefaultAllowed valuesDescription
service_namestring(required)<service path>gRPC service name.
idle_timeoutbadoption.Duration0<duration>Idle timeout. 0 disables.
ping_timeoutbadoption.Duration0<duration>Keepalive ping timeout. 0 disables PINGs.
permit_without_streamboolfalsetrue | falseAllow PINGs with no active stream.

Source: option/v2ray_transport.go:103-109 · pinned at v1.14.2 (af6e64c)

type: "quic" ​

The QUIC transport struct has no user-facing fields — it's just { "type": "quic" }. All QUIC tuning happens at the protocol layer (Hysteria2 / TUIC have their own native QUIC stacks).

type: "httpupgrade" ​

FieldTypeDefaultAllowed valuesDescription
hoststring(server address)<hostname>HTTP Host header.
pathstring//<path>HTTP path.
headersbadoption.HTTPHeader{}{<header>: <value or list>}Extra request headers.

Source: option/v2ray_transport.go:111-115 · pinned at v1.14.2 (af6e64c)

Examples ​

WebSocket + TLS:

json
{
  "outbounds": [{
    "type": "vless",
    "server": "example.com",
    "server_port": 443,
    "uuid": "...",
    "tls": {
      "enabled": true,
      "server_name": "example.com"
    },
    "transport": {
      "type": "ws",
      "path": "/vl",
      "headers": { "Host": "example.com" }
    }
  }]
}

gRPC + REALITY:

json
{
  "outbounds": [{
    "type": "vless",
    "server": "example.com",
    "server_port": 443,
    "uuid": "...",
    "tls": {
      "enabled": true,
      "server_name": "www.cloudflare.com",
      "utls": { "enabled": true, "fingerprint": "chrome" },
      "reality": { "enabled": true, "public_key": "...", "short_id": "..." }
    },
    "transport": {
      "type": "grpc",
      "service_name": "GunService",
      "idle_timeout": "60s",
      "ping_timeout": "20s",
      "permit_without_stream": true
    }
  }]
}

HTTP/2 (HTTP transport over TLS):

json
{
  "outbounds": [{
    "type": "vless",
    "server": "example.com",
    "server_port": 443,
    "uuid": "...",
    "tls": {
      "enabled": true,
      "server_name": "example.com",
      "alpn": ["h2"]
    },
    "transport": {
      "type": "http",
      "host": ["example.com"],
      "path": "/h2",
      "method": "PUT"
    }
  }]
}

Notes ​

  • sing-box does not ship a separate SplitHTTP / XHTTP transport. The closest equivalent is type: "http" (HTTP/2 over TLS); the HTTP transport has no HTTP/3 mode.
  • Keepalive PINGs are driven by idle_timeout alone: 0 (the default) sends none, and ping_timeout: 0 just means the 15s default. For long-lived connections behind NAT, set idle_timeout to something like "30s" so the underlying TCP connection sees periodic activity.
  • The host field on type: "http" is a list. The server uses it for SNI matching (any value matches); the client picks one randomly per request, useful when the upstream load balancer routes by Host header.
  • WebSocket early_data_header_name defaults to Sec-WebSocket-Protocol — the same header V2Ray uses. Override only when the upstream proxy strips that header.

Cross-core notes ​

  • Xray-core uses streamSettings.network + a per-transport *Settings block, with TCP, mKCP, and SplitHTTP/XHTTP variants that sing-box doesn't have. See Transport — Xray-core.
  • mihomo distributes transport settings across per-protocol *-opts blocks on each proxy entry. See Transport — mihomo.

Source: option/v2ray_transport.go:85-115 · v1.14.2 (af6e64c)

Core Tutorial by Argsment