Skip to content

Transport — Xray-core

Xray's transport choices live under streamSettings. The pattern is:

json
"streamSettings": {
  "network": "<transport>",
  "security": "<tls|reality|none>",
  "<transport>Settings": { ... }
}

network is one of tcp, ws, httpupgrade, grpc, mkcp, splithttp (now also known as XHTTP). The matching <transport>Settings block is read.

network: tcp

FieldTypeDefaultAllowed valuesDescription
headerjson.RawMessage{type: "none"}{type: "none"} | {type: "http", request: {...}, response: {...}}Optional header obfuscation. The default `none` is plain TCP. The HTTP header form sends a fake HTTP request/response to mimic plain web traffic.
acceptProxyProtocolboolfalsetrue | falseInbound — accept a PROXY-protocol v1/v2 header prepended by an upstream load balancer.

Source: infra/conf/transport_internet.go:108-111 · pinned at v26.6.1 (94ffd50)

tcpSettings is the default — most setups use plain TCP with TLS as the security layer.

network: ws — WebSocket

FieldTypeDefaultAllowed valuesDescription
hoststring(server address)<hostname>HTTP Host header sent on the WebSocket upgrade. Client priority: host > serverName > address.
pathstring//<path>[?ed=<bytes>]WebSocket path. The `?ed=N` query parameter enables 0-RTT early-data carrying up to N bytes.
headersmap[string]string{}{<header>: <value>}Extra HTTP headers. Putting `host` here is deprecated; use the top-level `host` field instead.
acceptProxyProtocolboolfalsetrue | falseInbound — accept PROXY-protocol on the underlying TCP connection.
heartbeatPerioduint320 (disabled)<seconds>Send WebSocket ping frames at this interval to keep NAT mappings alive. 0 disables.

Source: infra/conf/transport_internet.go:133-139 · pinned at v26.6.1 (94ffd50)

network: httpupgrade

A lighter cousin of WebSocket — uses the HTTP-upgrade handshake but not the full WebSocket framing afterwards. The post-handshake stream is plain bytes, saving a few percent CPU at the cost of WS framing benefits (e.g. close codes).

FieldTypeDefaultAllowed valuesDescription
hoststring(server address)<hostname>HTTP Host header.
pathstring//<path>[?ed=<bytes>]Path served. `?ed=N` enables early-data.
headersmap[string]string{}{<header>: <value>}Extra request headers. `host` is **not allowed** here — set it via the top-level `host` field.
acceptProxyProtocolboolfalsetrue | falseAccept PROXY-protocol on the underlying TCP connection.

Source: infra/conf/transport_internet.go:175-180 · pinned at v26.6.1 (94ffd50)

network: grpc

FieldTypeDefaultAllowed valuesDescription
authoritystring(server address)<authority>HTTP/2 :authority pseudo-header sent in the gRPC request.
serviceNamestring(required)<service path>gRPC service name. The full request path is `/{serviceName}/Tun` or `/{serviceName}/TunMulti` depending on `multiMode`.
multiModeboolfalsetrue | falseMultiplex many logical streams over one gRPC bidi stream. Reduces latency for short connections.
idle_timeoutint3260<seconds>Idle timeout for the gRPC connection. The peer is pinged after this interval; non-response closes the connection.
health_check_timeoutint3220<seconds>Timeout for the ping response.
permit_without_streamboolfalsetrue | falseAllow gRPC keepalive pings even with no active stream.
initial_windows_sizeint320 (lib default)<bytes>Initial HTTP/2 stream-level window size. Useful for high-BDP links.
user_agentstring(lib default)<UA string>User-Agent sent on the underlying HTTP/2 connection.

Source: infra/conf/grpc.go:8-17 · pinned at v26.6.1 (94ffd50)

network: mkcp

FieldTypeDefaultAllowed valuesDescription
mtu*uint321350>= 21Maximum mKCP segment size, in bytes. Must be at least 21.
tti*uint325010-1000 msTransmission-time interval in milliseconds (10–1000). Lower values mean snappier retransmits at the cost of CPU.
uplinkCapacity*uint325<MB/s>Estimated uplink bandwidth in MB/s. mKCP uses this to size its send window.
downlinkCapacity*uint3220<MB/s>Estimated downlink bandwidth in MB/s.
cwndMultiplier*uint32(default)>= 1Congestion-window multiplier — scales how aggressively mKCP grows its window. Must be at least 1. Replaces the old boolean `congestion` switch.
maxSendingWindow*uint32(default)>= mtuUpper bound on the sending window. Must be greater than or equal to `mtu`, otherwise the config is rejected at build.
headerjson.RawMessage(removed)(use finalmask)Removed. Setting either `header` or `seed` fails at build with a redirect to the new finalmask header transports.
seed*string(removed)(use finalmask)Removed. Same as `header`.

Source: infra/conf/transport_internet.go:53-63 · pinned at v26.6.1 (94ffd50)

network: splithttp (XHTTP)

XHTTP is Xray's modern HTTP-2/3-aware transport. It has 28 fields — this page documents the most-used ones; the rest are covered on the SplitHTTP page (Phase 5).

FieldTypeDefaultAllowed valuesDescription
hoststring(server address)<hostname>HTTP Host header.
pathstring//<path>Path prefix.
modestringautoauto | packet-up | stream-up | stream-oneSplitHTTP framing mode. `auto` negotiates with the server. `packet-up` sends each app-layer write as a separate POST; `stream-up` uses a single long-lived POST; `stream-one` keeps even the response open on the same TCP connection.
headersmap[string]string{}{<header>: <value>}Extra headers added to every request.
xPaddingBytesInt32Range(unset){from, to}Range of random padding bytes added to each request.
xmuxXmuxConfig(unset)XmuxConfigX-Mux connection-pool tuning.
downloadSettings*StreamConfig(unset)StreamConfigAlternate stream-settings for the **download** half (asymmetric setups, e.g. upload via SplitHTTP and download over plain TLS).

Source: infra/conf/transport_internet.go:211-240 · pinned at v26.6.1 (94ffd50)

The remaining fields cover advanced traffic-shaping (xPaddingObfsMode, xPaddingKey, seqPlacement, uplinkDataKey, …) and the X-Mux connection pool (maxConcurrency, maxConnections, cMaxReuseTimes, …).

Examples

WebSocket + TLS:

json
{
  "streamSettings": {
    "network": "ws",
    "security": "tls",
    "wsSettings": {
      "path": "/vl?ed=2048",
      "host": "example.com",
      "headers": { "User-Agent": "Mozilla/5.0..." }
    },
    "tlsSettings": { "serverName": "example.com" }
  }
}

gRPC + REALITY:

json
{
  "streamSettings": {
    "network": "grpc",
    "security": "reality",
    "grpcSettings": {
      "serviceName": "GunService",
      "multiMode": true,
      "idle_timeout": 60
    },
    "realitySettings": { /* ... */ }
  }
}

XHTTP + REALITY with asymmetric download:

json
{
  "streamSettings": {
    "network": "splithttp",
    "security": "reality",
    "splithttpSettings": {
      "mode": "auto",
      "path": "/xhttp",
      "host": "www.cloudflare.com",
      "xmux": {
        "maxConcurrency": { "from": 4, "to": 8 },
        "hMaxReusableSecs": { "from": 300, "to": 360 }
      },
      "downloadSettings": {
        "network": "splithttp",
        "security": "tls",
        "splithttpSettings": { "mode": "stream-one" }
      }
    },
    "realitySettings": { /* ... */ }
  }
}

Notes

  • network: "http" (HTTP/2 transport) was removed from Xray-core. Use splithttp (XHTTP) instead — it covers HTTP/2 and HTTP/3.
  • WebSocket path accepts a ?ed=<bytes> query parameter that encodes the maximum early-data size. The parameter is stripped from the on-wire path and applied as a transport setting at config build.
  • HttpUpgrade rejects host inside headers with an explicit error (infra/conf/transport_internet.go:206-208). WebSocket merely emits a deprecation warning for the same pattern.
  • mKCP's congestion model changed: the boolean congestion and the readBufferSize / writeBufferSize fields are removed, replaced by cwndMultiplier (window-growth multiplier, ≥ 1) and maxSendingWindow (window ceiling, ≥ mtu).
  • mKCP's header and seed fields are removed. Setting either fails at config build with a redirect to the new finalmask header transports (or the dedicated mkcp-original / mkcp-aes128gcm types).
  • finalmask is Xray's reworked UDP packet-masking subsystem (transport/internet/finalmask/*). It replaces the old mKCP header-obfuscation with pluggable building blocks selected by type — header-custom, mkcp-original, mkcp-aes128gcm, mkcp-legacy, realm, salamander, noise, xdns, xicmp, sudoku, fragment — including a small transform expression DSL for byte-level rewriting. It is an advanced area; see the upstream finalmask package for the full per-type schema.
  • XHTTP's downloadSettings enables asymmetric transport — the client uploads via one transport and downloads via another. Use to evade DPI that fingerprints the request/response symmetry of HTTP.
  • gRPC's idle_timeout and health_check_timeout use the snake_case spelling from the protobuf, not camelCase like the rest of Xray's surface.

Cross-core notes

  • sing-box uses a polymorphic transport: { type: "ws|http|grpc|httpupgrade|quic", ... } block embedded on every TLS-capable inbound/outbound. See Transport — sing-box.
  • mihomo distributes transport options across per-protocol *-opts blocks (ws-opts, h2-opts, grpc-opts, xhttp-opts) on each proxy entry. See Transport — mihomo.

Source: infra/conf/transport_internet.go:53-240 · v26.6.1 (94ffd50)

Core Tutorial by Argsment