Hysteria 2
Hysteria 2 is a QUIC-based proxy protocol. Because it runs over UDP, it often performs well on lossy or long-distance links where TCP-based protocols slow down. MeowX implements the Hysteria 2 client natively, including Salamander obfuscation and port hopping. Use it when your provider offers Hysteria 2 nodes and your network does not block or heavily throttle UDP.
Nodes use the mihomo / Clash Meta config format (type: hysteria2).
Minimal example
Section titled “Minimal example”proxies: - name: hy2-node type: hysteria2 server: example.com port: 443 password: your-passwordFull example
Section titled “Full example”proxies: - name: hy2-full type: hysteria2 server: 192.0.2.1 # port is optional when "ports" is set ports: "443,8443-8450" hop-interval: 30 password: your-password sni: example.com obfs: salamander obfs-password: your-obfs-passwordParameters
Section titled “Parameters”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | — | Node name. Must be unique and must not be a built-in name such as DIRECT or REJECT. |
type |
string | Yes | — | hysteria2. |
server |
string | Yes | — | Server domain name or IP address. |
port |
integer | Yes, unless ports is set |
— | Server UDP port. Ignored when ports is set. |
password |
string | Yes | — | Authentication password sent to the server. |
sni |
string | No | value of servername, then server |
TLS server name sent in the QUIC handshake. |
servername |
string | No | — | Accepted as an alias of sni; sni wins if both are set. |
obfs |
string | No | none | Obfuscation type. Only salamander (case-insensitive) is supported. Empty means no obfuscation. |
obfs-password |
string | Required with obfs |
— | Salamander password. Must be non-empty and must match the server. |
ports |
string | No | — | Port hopping range, e.g. "443,8443-8450". See Port hopping. |
hop-interval |
integer or string | No | 30 |
Seconds between hops: a number (30, 30s) or a random range (10-30). Only used with ports. |
skip-cert-verify |
boolean | No | false |
Skip verification of the server certificate. Needed for self-signed certificates. See Certificates. |
dialer-proxy |
string | No | — | Not supported for Hysteria 2 — see Chained proxies. |
Ignored fields
Section titled “Ignored fields”These common mihomo fields are accepted in the file but have no effect:
up,down— bandwidth hints for the Brutal congestion controller. Brutal is not implemented; MeowX uses the QUIC library’s standard congestion control.alpn— the ALPN is alwaysh3.fingerprint,ca,ca-str— certificate pinning and custom CAs are not supported; see Certificates.udp— UDP is always available on Hysteria 2 nodes, whatever this field says.udp-mtu,cwnd,fast-openand other tuning options.
Port hopping
Section titled “Port hopping”When ports is set, MeowX connects to a random port from the list and, every hop-interval seconds, moves the connection to a new random port. Each hop opens a new local UDP socket; the old socket keeps receiving for one more round so in-flight replies are not lost. The QUIC connection itself — and every proxied connection riding on it — continues uninterrupted.
Rules for ports:
- Comma-separated (
,) or slash-separated (/) items. - Each item is a single port (
443) or a range (8443-8450). A reversed range (8450-8443) is accepted. - Port
0is invalid. Overlapping ranges are merged, so every port has the same chance of being picked. - When
portsis present,portis ignored and may be omitted.
Rules for hop-interval:
- A positive number of seconds, with or without a trailing
s. - A range such as
10-30picks a random interval in that range before each hop. - Values shorter than 5 seconds are raised to 5 seconds.
- Omitted: 30 seconds.
Port hopping requires a server that accepts traffic on all of those ports — usually a single Hysteria 2 listener with a firewall rule (for example a DNAT rule) forwarding the whole range to it.
Salamander obfuscation
Section titled “Salamander obfuscation”With obfs: salamander, every UDP packet is scrambled with a key derived from obfs-password, so the traffic no longer looks like QUIC. The server must have Salamander enabled with the same password.
- UDP is always supported and is full-cone: one session can talk to many destinations, and replies from any of them come back.
- All TCP connections through a node share a single QUIC connection. Each UDP session uses its own QUIC connection.
Chained proxies
Section titled “Chained proxies”dialer-proxy cannot be used on a Hysteria 2 node: QUIC runs over UDP and cannot be carried through a TCP proxy. A Hysteria 2 node with dialer-proxy is skipped (a warning appears in the logs). A Hysteria 2 node can still be the target of another node’s dialer-proxy — see Chained proxies.
Certificates
Section titled “Certificates”MeowX verifies the Hysteria 2 server certificate against the system’s trusted root certificates, matching it against the SNI (sni, or server when no SNI is set — an IP address is matched against the certificate’s IP entries). Missing intermediate certificates are fetched automatically. Verification happens right after the QUIC handshake and before your password is sent, so a server with the wrong certificate never receives it.
If the server uses a self-signed certificate, or a certificate that doesn’t match the name you connect to, the connection fails with “server certificate not trusted”. Set skip-cert-verify: true on that node to connect anyway:
skip-cert-verify: trueServers that check SNI (sniGuard)
Section titled “Servers that check SNI (sniGuard)”If sni is not set, MeowX sends the value of server as the SNI — even when it is an IP address. The official Hysteria 2 server checks the SNI by default (sniGuard: dns-san): when its certificate contains a domain name and the SNI does not match it, the server aborts the handshake. The official client behaves the same way, so this is a server-side configuration matter.
If a node whose server is an IP address cannot connect, set sni to the domain in the server’s certificate:
server: 192.0.2.1 sni: example.comValidation
Section titled “Validation”| Problem | Result |
|---|---|
password missing or empty |
The whole configuration fails to load. |
Neither port nor a non-empty ports |
The whole configuration fails to load. |
obfs is anything other than salamander |
Node is dropped with a warning. |
obfs: salamander without obfs-password |
Node is dropped with a warning. |
ports cannot be parsed (e.g. contains 0, letters, or empty items) |
Node is dropped with a warning. |
ports is set and hop-interval is not a positive number or a-b range |
Node is dropped with a warning. |
dialer-proxy is set |
Node is skipped with a warning in the logs. |
Dropped nodes do not break the rest of the subscription. Warnings appear in the app’s logs.
