Skip to content

Transport — mihomo

mihomo distributes transport options across *-opts blocks on each proxy entry. There is no consolidated transport struct: the choice of transport is the proxy's network field, and the matching options block is read.

The network selector

Every TLS-capable mihomo proxy has a network: field. Values:

ValueMeaning
tcp (default)Plain TCP; ignore all *-opts blocks.
wsWebSocket — read ws-opts.
httpPlain HTTP disguise (no upgrade) — read http-opts.
h2HTTP/2 — read h2-opts.
grpcgRPC over HTTP/2 — read grpc-opts.
xhttpXTLS HTTP framing (Xray-compatible) — read xhttp-opts.

A few protocols add extras (e.g. Trojan supports ws and grpc only; VMess adds http and h2). The matrix is documented per protocol.

ws-opts

FieldTypeDefaultAllowed valuesDescription
pathstring//<path>WebSocket path. The `?ed=N` early-data query parameter is supported, matching Xray's convention.
headersmap[string]string{}{<header>: <value>}Extra HTTP headers on the upgrade request.
max-early-dataint0<bytes>Maximum bytes of 0-RTT early data buffered before the WS handshake completes.
early-data-header-namestring(unset)<header name>Header used to carry the base64-encoded early data when the server expects it under a custom name.
v2ray-http-upgradeboolfalsetrue | falseUse the V2Ray HTTP-upgrade transport instead of true WebSocket — saves the post-handshake framing overhead.
v2ray-http-upgrade-fast-openboolfalsetrue | falsePiggyback the client payload onto the HTTP-upgrade request itself to save one RTT.

Source: adapter/outbound/vmess.go:94-101 · pinned at v1.19.27 (5184081)

http-opts — HTTP disguise

FieldTypeDefaultAllowed valuesDescription
methodstringGET<HTTP method>HTTP method used by the disguise transport.
path[]string[/][/<path>]List of paths to rotate across. Client picks one per request.
headersmap[string][]string{}{<header>: [<value>]}Map of header name to list of values. Client picks one value per request.

Source: adapter/outbound/vmess.go:74-78 · pinned at v1.19.27 (5184081)

h2-opts — HTTP/2

FieldTypeDefaultAllowed valuesDescription
host[]string[][<hostname>]List of Host header values. Client picks one randomly per request.
pathstring//<path>HTTP path.

Source: adapter/outbound/vmess.go:80-83 · pinned at v1.19.27 (5184081)

grpc-opts

FieldTypeDefaultAllowed valuesDescription
grpc-service-namestring(required)<service name>gRPC service name path.
grpc-user-agentstring(unset)<UA string>Override the gRPC client User-Agent.
ping-intervalint0<seconds>HTTP/2 PING frame interval. 0 disables.
max-connectionsint0<int>Max concurrent gRPC channels (mux fan-out).
min-streamsint0<int>Minimum streams per channel before allocating a new channel.
max-streamsint0<int>Maximum streams per channel.

Source: adapter/outbound/vmess.go:85-92 · pinned at v1.19.27 (5184081)

xhttp-opts

The XHTTP block carries 23 fields matching Xray's SplitHTTP. The most-used ones are path, host, mode, plus the x-padding-* and session-related fields for traffic shaping. Reuse settings sit in the nested reuse-settings sub-block; asymmetric download configuration in download-settings. Refer to the VLESS — mihomo page for the full struct (it's shared between VLESS and other XHTTP-capable proxies).

Examples

WebSocket — common VMess shape:

yaml
proxies:
  - name: vmess-ws
    type: vmess
    server: example.com
    port: 443
    uuid: <UUID>
    cipher: auto
    network: ws
    tls: true
    servername: example.com
    ws-opts:
      path: /vm
      headers:
        Host: example.com
      max-early-data: 2048
      early-data-header-name: Sec-WebSocket-Protocol

gRPC + REALITY (VLESS):

yaml
proxies:
  - name: vless-grpc-reality
    type: vless
    server: example.com
    port: 443
    uuid: <UUID>
    flow: xtls-rprx-vision
    tls: true
    servername: www.cloudflare.com
    client-fingerprint: chrome
    network: grpc
    reality-opts:
      public-key: <base64>
      short-id: <hex>
    grpc-opts:
      grpc-service-name: GunService

V2Ray HTTP-upgrade (alternative to WS, lower CPU):

yaml
proxies:
  - name: vmess-httpupgrade
    type: vmess
    server: example.com
    port: 443
    uuid: <UUID>
    cipher: auto
    network: ws
    tls: true
    servername: example.com
    ws-opts:
      path: /up
      v2ray-http-upgrade: true
      v2ray-http-upgrade-fast-open: true

Notes

  • mihomo's network: ws covers both standard WebSocket and the V2Ray-style HTTP-upgrade transport (via the v2ray-http-upgrade toggle in ws-opts). There is no separate network: httpupgrade value.
  • network: http is the legacy V2Ray HTTP disguise (plain HTTP/1.1 with fake methods). Don't confuse with network: h2 (real HTTP/2) or network: xhttp (Xray's modern XTLS framing).
  • http-opts.path and http-opts.headers are randomized per request — mihomo picks one value from each list for each new connection.
  • ws-opts.v2ray-http-upgrade-fast-open saves one RTT by sending the client payload alongside the upgrade request. Servers that buffer the full upgrade before responding (some load balancers) will reject this; test both before deploying.
  • xhttp-opts is the Xray-compat path for clients that need to talk to Xray's network: splithttp servers. The field names match Xray's SplitHTTP exactly (kebab-cased).

Cross-core notes

  • Xray-core uses streamSettings.network + a per-transport *Settings block. Has TCP-with-header-obfs, mKCP, and SplitHTTP variants that mihomo doesn't expose under those names. See Transport — Xray-core.
  • sing-box uses a polymorphic transport: { type, ... } block embedded on every proxy. See Transport — sing-box.

Source: adapter/outbound/vmess.go:74-101 · v1.19.27 (5184081)

Core Tutorial by Argsment