Skip to content

Routing — mihomo

mihomo's routing engine is a list of compact one-line rule strings under the top-level rules: key. Each rule has the form:

<TYPE>,<payload>,<target>[,no-resolve][,src]

Rules are evaluated in declaration order; the first matching rule wins. The target is either a proxy name, a proxy-group name, or one of the built-in DIRECT / REJECT / COMPATIBLE names.

Rule types

mihomo defines 30+ rule types. The most commonly used:

Destination matchers

TypePayloadExample
DOMAINexact domainDOMAIN,example.com,proxy
DOMAIN-SUFFIXsuffix match (any subdomain)DOMAIN-SUFFIX,example.com,proxy
DOMAIN-KEYWORDsubstring match in any labelDOMAIN-KEYWORD,google,proxy
DOMAIN-REGEXRE2 regex against the full domainDOMAIN-REGEX,^([a-z]+)\.cdn\.example$,proxy
DOMAIN-WILDCARDglob with * (and + matches one label)DOMAIN-WILDCARD,*.example.com,proxy
GEOSITEcategory from geosite.dat / MaxMindGEOSITE,category-ads,REJECT
GEOIPcategory from geoip.dat / MaxMindGEOIP,CN,DIRECT
IP-CIDRCIDR matchIP-CIDR,10.0.0.0/8,DIRECT,no-resolve
IP-SUFFIXmatch by trailing IP bitsIP-SUFFIX,::1/128,DIRECT
IP-ASNASN from MaxMindIP-ASN,13335,proxy

Source matchers

TypePayloadExample
SRC-IP-CIDRsource CIDRSRC-IP-CIDR,192.168.1.0/24,DIRECT
SRC-IP-SUFFIXsource IP-suffixSRC-IP-SUFFIX,::1/128,DIRECT
SRC-GEOIPsource GeoIP categorySRC-GEOIP,CN,DIRECT
SRC-IP-ASNsource ASNSRC-IP-ASN,4134,DIRECT
SRC-PORTsource-port rangeSRC-PORT,53,DNS
IN-PORTinbound listener portIN-PORT,8388,DIRECT
IN-USERinbound auth userIN-USER,alice,proxy
IN-NAMEinbound listener nameIN-NAME,vless-in,proxy
IN-TYPEinbound listener typeIN-TYPE,SOCKS5,proxy

Connection matchers

TypePayloadExample
DST-PORTdestination port (single, range, list)DST-PORT,443,proxy
NETWORKtcp or udpNETWORK,udp,proxy-udp
DSCPDSCP valueDSCP,46,proxy-priority
UIDlocal user ID (Linux/macOS)UID,1000,proxy

Process matchers

TypePayloadExample
PROCESS-NAMEprocess basenamePROCESS-NAME,curl,proxy
PROCESS-PATHabsolute pathPROCESS-PATH,/usr/bin/curl,proxy
PROCESS-NAME-REGEX / PROCESS-PATH-REGEXregexPROCESS-NAME-REGEX,^chrome.*$,proxy
PROCESS-NAME-WILDCARD / PROCESS-PATH-WILDCARDglobPROCESS-NAME-WILDCARD,fire*,proxy

Set & combinator types

TypePayloadExample
RULE-SETrule-set name (declared in rule-providers)RULE-SET,gfw,proxy
SUB-RULEnamed sub-rule (declared in sub-rules)SUB-RULE,(NETWORK,udp),sub-udp
AND / OR / NOTboolean combinatorsAND,((DOMAIN-SUFFIX,com),(IP-CIDR,1.0.0.0/8)),proxy
MATCHunconditional defaultMATCH,proxy

Modifiers

After the target, two optional comma-separated modifiers are allowed:

  • no-resolve — for IP/GEOIP rules, do not resolve a destination domain to IP for matching. Speeds up the rule but trades accuracy.
  • src — for IP-suffix rules, match on the source IP instead of the destination IP.

rule-providers

Top-level rule-providers: declares named rule sources you reference from RULE-SET rules. Two transport types and three formats:

yaml
rule-providers:
  geosite-cn:
    type: http
    behavior: domain        # 'domain', 'ipcidr', or 'classical'
    format: mrs             # 'yaml', 'text', or 'mrs' (binary)
    url: https://example.com/geosite-cn.mrs
    interval: 86400         # refresh interval in seconds
    path: ./rule-providers/geosite-cn.mrs
    proxy: DIRECT           # outbound used for the download

  local-block:
    type: file
    behavior: classical
    format: yaml
    path: ./rule-providers/block.yaml

Behaviors:

  • domain — payload is one domain per line. Fast.
  • ipcidr — payload is one CIDR per line.
  • classical — payload is full mihomo rule strings (everything except the target). Slower but most flexible.

sub-rules

Top-level sub-rules: declares named sub-rule lists you can call into with SUB-RULE. Useful for nesting rule logic without duplicating it.

yaml
sub-rules:
  sub-udp:
    - GEOIP,CN,DIRECT
    - MATCH,udp-proxy

rules:
  - SUB-RULE,(NETWORK,udp),sub-udp
  - MATCH,proxy

Examples

Classic CN-bypass routing:

yaml
rules:
  - DOMAIN-SUFFIX,local,DIRECT
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - GEOSITE,cn,DIRECT
  - GEOIP,CN,DIRECT
  - MATCH,proxy

Process-based split:

yaml
rules:
  - PROCESS-NAME,curl,DIRECT
  - PROCESS-NAME-WILDCARD,fire*,proxy
  - MATCH,DIRECT

Boolean combinators:

yaml
rules:
  - AND,((NETWORK,udp),(DST-PORT,443)),quic-proxy
  - OR,((DOMAIN-SUFFIX,onion),(GEOSITE,private)),tor
  - NOT,((GEOIP,CN)),proxy
  - MATCH,DIRECT

Using rule-providers with a RULE-SET rule:

yaml
rule-providers:
  gfw:
    type: http
    behavior: domain
    format: mrs
    url: https://example.com/gfw.mrs
    interval: 86400
    path: ./providers/gfw.mrs

rules:
  - RULE-SET,gfw,proxy
  - MATCH,DIRECT

Notes

  • Rules are evaluated in order. Put no-resolve modifiers on IP rules early in the list to avoid one DNS lookup per connection for obvious-local traffic.
  • The GEOSITE / GEOIP rule types read from geoip.dat / Country.mmdb and geosite.dat. URL overrides live under the top-level geox-url block.
  • The combinator syntax (AND,(<rule>,<rule>),target) uses parentheses around each nested rule. The nested rules omit the target — the target on the outer combinator applies.
  • RULE-SET rules ignore the no-resolve / src modifiers on the outer rule; instead set those properties on the rule-provider declaration itself.
  • mihomo has no final field. Use a MATCH,<target> at the end of rules: for the catch-all behavior.

Cross-core notes

  • Xray-core uses structured JSON rules with per-criterion fields and a polymorphic match shape. There is no compact-string form. See Routing — Xray-core.
  • sing-box uses structured rules too, but with explicit action enums (route / direct / bypass / reject / hijack-dns / sniff / resolve) and a separate rule_set block for named rule lists. See Routing — sing-box.

Core Tutorial by Argsment