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):
| Field | Type | Default | Description |
|---|---|---|---|
tls | bool | false | Master switch — wrap the stream in TLS. Some protocols (Hysteria2, TUIC, AnyTLS) require TLS and ignore this flag. |
sni | string | (server name) | TLS Server Name Indication. Defaults to the server field. |
servername | string | (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-verify | bool | false | Disable certificate verification. Use only for testing. |
fingerprint | string | (unset) | Pin the server certificate to a SHA-256 fingerprint (lowercase hex, no colons). |
certificate | string | (unset) | Client certificate for mTLS. |
private-key | string | (unset) | Private key matching certificate. |
client-fingerprint | string | (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:
| Field | Type | Default | Description |
|---|---|---|---|
certificate | string | (required) | Server certificate (path or inline PEM). |
private-key | string | (required) | Server private key. |
client-auth-type | string | no-client-cert | Mutual-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-cert | string | (unset) | CA bundle accepted as client roots when client-auth-type requires verification. |
ech-key | string | (unset) | ECH configuration material. See ECH. |
client-fingerprint values
mihomo's uTLS implementation accepts:
| Value | Mimics |
|---|---|
chrome | Chrome 100+ |
firefox | Firefox 102+ |
safari | Safari 16+ |
ios | iOS Safari 16+ |
android | Android Chrome |
edge | Edge Chromium |
360 | 360 Secure Browser |
qq | QQ Browser |
random | Pick one of the above randomly per connection |
randomized | Generate 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-leveltls: trueinstead and leave these alone.
Where to set TLS in mihomo
Three places to keep in mind:
- Per-outbound — directly on the proxy entry in
proxies:. This is the typical place for client-side TLS. - Per-inbound — on the listener entry in
listeners:. Thecertificate/private-keypair plus optional mTLS fields. - Top-level
tls:block — see TLS. Only used byexternal-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) andstreamSettings.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.
