REALITY — mihomo
mihomo supports REALITY on both sides. Outbound uses reality-opts: embedded in the proxy entry; inbound uses reality-config: on the listener.
Outbound — reality-opts
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
public-key | string | (required) | <base64 X25519 public key> | Server X25519 public key. Generated by the server admin via mihomo's `generate reality-keypair` or Xray's `xray x25519`. |
short-id | string | (unset) | <hex string> | Short ID announced to the server. Must match one of the server's `short-id` entries (or be empty if the server lists `""`). |
support-x25519mlkem768 | bool | false | true | false | Advertise post-quantum X25519MLKEM768 hybrid key exchange. Server must support the matching curve. |
Source: adapter/outbound/reality.go:13-18 · pinned at v1.19.27 (5184081)
Inbound — reality-config
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
dest | string | (required) | <host:port> | Camouflage target — the legitimate site whose TLS handshake is proxied for unauthorized connections. The site's cert must be valid; mihomo verifies it during handshake forwarding. |
private-key | string | (required) | <base64 X25519 private key> | Server X25519 private key. |
short-id | []string | [] | [<hex string>] | List of allowed short IDs (hex, even length, ≤ 16 chars). Include `""` to allow clients that don't advertise a short ID. |
server-names | []string | (required) | [<hostname>] | Acceptable SNI values. Connections with a different SNI are forwarded to `dest` (camouflage fallback). |
max-time-difference | int | 0 (no limit) | <seconds> | Maximum tolerated clock skew between client and server, in seconds. 0 disables the check. |
proxy | string | (direct) | <proxy name> | Route the camouflage-fallback traffic through a named outbound proxy instead of dialing `dest` directly. Useful when the camouflage site can't be reached from the server. |
limit-fallback-upload | RealityLimitFallback | (unset) | RealityLimitFallback | Rate-limit the camouflage-fallback upload direction. Use to make REALITY traffic indistinguishable from a slow legitimate site. |
limit-fallback-download | RealityLimitFallback | (unset) | RealityLimitFallback | Rate-limit the camouflage-fallback download direction. |
Source: listener/inbound/reality.go:5-15 · pinned at v1.19.27 (5184081)
limit-fallback-upload / limit-fallback-download
| Field | Type | Default | Allowed values | Description |
|---|---|---|---|---|
after-bytes | uint64 | 0 | <bytes> | Apply the rate cap only after this many bytes have flowed through. 0 caps from the first byte. |
bytes-per-sec | uint64 | 0 (no limit) | <bytes> | Sustained bandwidth cap in bytes per second. 0 disables the cap. |
burst-bytes-per-sec | uint64 | 0 (=bytes-per-sec) | <bytes> | Burst bandwidth cap. 0 keeps the same as `bytes-per-sec` (no burst). |
Source: listener/inbound/reality.go:17-21 · pinned at v1.19.27 (5184081)
Key generation
mihomo includes a key generator:
sh
$ mihomo generate reality-keypair
PrivateKey: <base64-private-key>
PublicKey: <base64-public-key>Xray's xray x25519 produces the same format (both use X25519 in base64-RawURLEncoding) — keys are interchangeable across the three cores.
Examples
Outbound — VLESS with REALITY:
yaml
proxies:
- name: vless-reality
type: vless
server: your.server.example
port: 443
uuid: <UUID>
flow: xtls-rprx-vision
tls: true
servername: www.cloudflare.com
client-fingerprint: chrome
reality-opts:
public-key: <base64-public-key>
short-id: 0123456789abcdefInbound — VLESS listener with REALITY server-side:
yaml
listeners:
- name: vless-reality-in
type: vless
listen: 0.0.0.0
port: 443
users:
- username: alice
uuid: <UUID>
flow: xtls-rprx-vision
reality-config:
dest: www.cloudflare.com:443
private-key: <base64-private-key>
short-id:
- ''
- 0123456789abcdef
server-names:
- www.cloudflare.com
max-time-difference: 60
limit-fallback-upload:
bytes-per-sec: 8388608
burst-bytes-per-sec: 16777216
limit-fallback-download:
bytes-per-sec: 12582912Notes
support-x25519mlkem768on the outbound enables the hybrid post-quantum key exchange added in 2024. Servers built against a matching curve list will accept it; older servers see a regular X25519 handshake.- The inbound's
proxy:field routes the camouflage fallback through another mihomo outbound. This is unique to mihomo — useful when the server can't directly reach the camouflage site (sing-box and Xray always direct-dialdest). limit-fallback-upload.after-bytesis the warm-up: the cap kicks in only after this many bytes. Use a small value (~100 KB) so the camouflage handshake itself isn't throttled.- Setting
max-time-difference: 60(one minute) is generous enough for servers without NTP. Setting it to 0 disables clock-skew checks entirely — convenient for development, risky for production.
Cross-core notes
- Xray-core keeps everything in a single
REALITYConfig. The camouflage target isdest; uTLS fingerprint sits on the same struct asfingerprint. See REALITY — Xray-core. - sing-box nests REALITY inside the embedded
tls:block on both sides. The camouflage target is a sub-block calledhandshake(which embeds ServerOptions + DialerOptions). See REALITY — sing-box.
Source: adapter/outbound/reality.go:13-18 · v1.19.27 (5184081)
