Skip to content

TLS in mihomo — overview

Unlike Xray and sing-box, mihomo does not have a consolidated TLS block. Each proxy adapter and each listener inbound carries its own set of TLS-related fields directly on the proxy object. This page documents the recurring field set so you don't have to re-discover it on every protocol page.

The common TLS field set

These fields appear on virtually every mihomo outbound that speaks TLS (VLESS, VMess, Trojan, Hysteria2, TUIC, AnyTLS, HTTP, SOCKS, plain Shadowsocks via plugins):

FieldTypeDefaultDescription
tlsboolfalseMaster switch — wrap the stream in TLS. Some protocols (Hysteria2, TUIC, AnyTLS) require TLS and ignore this flag.
snistring(server name)TLS Server Name Indication. Defaults to the server field.
servernamestring(sni)Alternate name (older adapters). Equivalent to sni.
alpn[]string(none)ALPN list offered during the TLS handshake. Typical values: [h2, http/1.1] for VLESS/VMess/Trojan; [h3] for HTTP/3 protocols.
skip-cert-verifyboolfalseDisable certificate verification. Use only for testing.
fingerprintstring(unset)Pin the server certificate to a SHA-256 fingerprint (lowercase hex, no colons).
certificatestring(unset)Client certificate for mTLS.
private-keystring(unset)Private key matching certificate.
client-fingerprintstring(global)uTLS client-hello fingerprint. Falls back to the top-level global-client-fingerprint.

The matching set on the inbound listener side is slightly different:

FieldTypeDefaultDescription
certificatestring(required)Server certificate (path or inline PEM).
private-keystring(required)Server private key.
client-auth-typestringno-client-certMutual-TLS client-auth mode. Five values: no-client-cert, request-client-cert, require-any-client-cert, verify-client-cert-if-given, require-and-verify-client-cert.
client-auth-certstring(unset)CA bundle accepted as client roots when client-auth-type requires verification.
ech-keystring(unset)ECH configuration material. See ECH.

client-fingerprint values

mihomo's uTLS implementation accepts:

ValueMimics
chromeChrome 100+
firefoxFirefox 102+
safariSafari 16+
iosiOS Safari 16+
androidAndroid Chrome
edgeEdge Chromium
360360 Secure Browser
qqQQ Browser
randomPick one of the above randomly per connection
randomizedGenerate a synthetic randomized fingerprint each connection

If neither the per-proxy client-fingerprint nor the top-level global-client-fingerprint is set, mihomo emits a standard Go crypto/tls ClientHello (recognizable as "not a browser" by DPI).

TLS-bearing sub-blocks

When a protocol needs settings beyond the flat field set, mihomo nests them in named sub-blocks. The most common are:

  • reality-opts — REALITY client-side configuration.
  • ech-opts — Encrypted Client Hello configuration.
  • ws-opts.tls, grpc-opts.tls, h2-opts.tls — transport-layer TLS toggles inside a transport block. Most users set the protocol-level tls: true instead and leave these alone.

Where to set TLS in mihomo

Three places to keep in mind:

  1. Per-outbound — directly on the proxy entry in proxies:. This is the typical place for client-side TLS.
  2. Per-inbound — on the listener entry in listeners:. The certificate / private-key pair plus optional mTLS fields.
  3. Top-level tls: block — see TLS. Only used by external-controller-tls (the Clash API endpoint). It is not a default for proxy adapters.

Cross-core notes

  • Xray-core consolidates everything under streamSettings.tlsSettings (per-connection) and streamSettings.security: "tls". See TLS — Xray-core.
  • sing-box uses a single embedded tls: { ... } block on every inbound and outbound, with REALITY / ECH / uTLS as sub-fields. See TLS — sing-box.

Core Tutorial by Argsment