a colorful toy on a table

The previous article on multi-gateway home network architecture covered the overall design but didn’t dive into the details of writing rules. This post focuses specifically on Mihomo’s traffic splitting rules, breaking down everything from syntax basics to practical configuration templates.

Basic Concepts of Rules

Mihomo controls traffic splitting through the rules field. Each rule follows this format:

rule-type,match-value,proxy-group

For example:

rules:
  - DOMAIN-SUFFIX,google.com,Proxy
  - IP-CIDR,192.168.0.0/16,DIRECT
  - GEOIP,CN,DIRECT
  - MATCH,Proxy          # fallback rule — matches all remaining traffic

Rules are matched in order — the first rule that matches is executed, and subsequent rules are skipped. Order is critical.

Rule Types Explained

Domain-Based Rules

# Exact domain match
- DOMAIN,www.google.com,Proxy

# Match domain and all subdomains (most common)
- DOMAIN-SUFFIX,google.com,Proxy
# Covers: google.com / mail.google.com / api.google.com

# Domain keyword (poor performance, rarely used)
- DOMAIN-KEYWORD,google,Proxy
# Matches any domain containing "google"

# Regular expressions (most flexible, slowest)
- DOMAIN-REGEX,^.*\.google\.com$,Proxy

Priority recommendation: DOMAIN > DOMAIN-SUFFIX > DOMAIN-KEYWORD

Place more specific rules earlier for better performance and to avoid false matches.

IP-Based Rules

# IPv4 CIDR
- IP-CIDR,192.168.0.0/16,DIRECT
- IP-CIDR,10.0.0.0/8,DIRECT
- IP-CIDR,172.16.0.0/12,DIRECT

# IPv6 CIDR
- IP-CIDR6,::1/128,DIRECT

# Note: IP-CIDR triggers DNS resolution, which impacts performance on traffic before pure domain rules
# It's recommended to add the no-resolve suffix to skip DNS resolution and match the connection IP directly
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve

GeoIP Rules

Route traffic based on the country where the IP is registered:

# Mainland China IPs — direct connection
- GEOIP,CN,DIRECT

# Private IPs — direct connection
- GEOIP,PRIVATE,DIRECT,no-resolve

The GeoIP database comes from MaxMind and is automatically updated by Mihomo. It’s not 100% accurate, but sufficient for most scenarios.

Process Rules (Desktop Clients Only)

Route traffic based on the name of the process making the request:

# Specific apps through proxy
- PROCESS-NAME,curl,Proxy
- PROCESS-NAME,wget,Proxy

# Development tools — direct connection
- PROCESS-NAME,node,DIRECT

Port Rules

# Specific destination port
- DST-PORT,80,DIRECT
- DST-PORT,443,Proxy

# Port range
- DST-PORT,3000-3999,DIRECT

Fallback Rule

# MATCH must go last — it matches all traffic not caught by previous rules
- MATCH,Proxy

Rule Providers (Rule Sets)

Writing every domain manually isn’t practical. Mihomo supports importing external rule providers:

rule-providers:
  reject:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/reject.txt"
    path: ./ruleset/reject.yaml
    interval: 86400   # Update once daily

  direct:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/direct.txt"
    path: ./ruleset/direct.yaml
    interval: 86400

  proxy:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/proxy.txt"
    path: ./ruleset/proxy.yaml
    interval: 86400

  gfw:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/gfw.txt"
    path: ./ruleset/gfw.yaml
    interval: 86400

  cn-cidr:
    type: http
    behavior: ipcidr
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/cncidr.txt"
    path: ./ruleset/cncidr.yaml
    interval: 86400

rules:
  - RULE-SET,reject,REJECT         # ad/malware domain blocking
  - RULE-SET,direct,DIRECT         # known direct domains
  - RULE-SET,proxy,Proxy            # known proxy domains
  - RULE-SET,gfw,Proxy              # GFW-blocked domains
  - RULE-SET,cn-cidr,DIRECT        # mainland China IP ranges
  - GEOIP,CN,DIRECT
  - MATCH,Proxy

Loyalsoldier/clash-rules is the best-maintained rule set available today, with comprehensive coverage and regular updates.

Complete Configuration Template

Below is the configuration structure I actually use, suitable for multi-node + fine-grained traffic splitting scenarios:

# ── Proxy Nodes ──
proxies:
  - name: "DMIT-HK-Reality"
    type: vless
    server: 43.x.x.x
    port: 443
    uuid: Your UUID
    flow: xtls-rprx-vision
    reality-opts:
      public-key: Your public key
    servername: www.apple.com
    client-fingerprint: chrome
    tls: true

  - name: "DMIT-HK-Hysteria2"
    type: hysteria2
    server: 43.x.x.x
    port: 443
    password: Your password
    sni: bing.com
    skip-cert-verify: true

  - name: "DMIT-US"
    type: vless
    # ... US node configuration

# ── Proxy Groups ──
proxy-groups:
  # Primary Hong Kong nodes (auto-select fastest)
  - name: "Hong Kong"
    type: url-test
    url: http://www.gstatic.com/generate_204
    interval: 60
    tolerance: 50
    proxies:
      - DMIT-HK-Reality
      - DMIT-HK-Hysteria2

  # Backup US
  - name: "US"
    type: url-test
    interval: 60
    proxies:
      - DMIT-US

  # Automatic failover
  - name: "Proxy"
    type: fallback
    url: http://www.gstatic.com/generate_204
    interval: 30
    proxies:
      - Hong Kong
      - US

  # Manual selection (for special cases)
  - name: "Manual"
    type: select
    proxies:
      - DMIT-HK-Reality
      - DMIT-HK-Hysteria2
      - DMIT-US
      - DIRECT

  # Streaming (using native IPs for unlocking)
  - name: "Streaming"
    type: select
    proxies:
      - DMIT-HK-Reality
      - DMIT-US

  # AI tools (requires specific regional IPs)
  - name: "AI Tools"
    type: select
    proxies:
      - DMIT-US
      - DMIT-HK-Reality

# ── Rule Providers ──
rule-providers:
  reject:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/reject.txt"
    path: ./ruleset/reject.yaml
    interval: 86400
  direct:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/direct.txt"
    path: ./ruleset/direct.yaml
    interval: 86400
  proxy:
    type: http
    behavior: domain
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/proxy.txt"
    path: ./ruleset/proxy.yaml
    interval: 86400
  cn-cidr:
    type: http
    behavior: ipcidr
    url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/cncidr.txt"
    path: ./ruleset/cncidr.yaml
    interval: 86400

# ── Traffic Rules ──
rules:
  # Ad blocking
  - RULE-SET,reject,REJECT

  # Private IPs — direct
  - GEOIP,PRIVATE,DIRECT,no-resolve

  # AI tools use US nodes
  - DOMAIN-SUFFIX,openai.com,AI Tools
  - DOMAIN-SUFFIX,anthropic.com,AI Tools
  - DOMAIN-SUFFIX,claude.ai,AI Tools
  - DOMAIN-KEYWORD,openai,AI Tools

  # Streaming
  - DOMAIN-SUFFIX,netflix.com,Streaming
  - DOMAIN-SUFFIX,nflxvideo.net,Streaming
  - DOMAIN-SUFFIX,spotify.com,Streaming
  - DOMAIN-SUFFIX,disneyplus.com,Streaming

  # Mainland China — direct (rule set)
  - RULE-SET,direct,DIRECT

  # Proxy rule set
  - RULE-SET,proxy,Proxy

  # Mainland China IPs — direct
  - RULE-SET,cn-cidr,DIRECT,no-resolve
  - GEOIP,CN,DIRECT

  # Fallback to proxy
  - MATCH,Proxy

DNS Configuration (Preventing DNS Leaks)

If rules are configured but DNS isn’t set up properly, it can leak your real IP or cause rules to not work:

dns:
  enable: true
  listen: 0.0.0.0:53
  enhanced-mode: fake-ip         # or redir-host; fake-ip is preferred
  fake-ip-range: 198.18.0.0/15
  fake-ip-filter:                # These domains bypass fake-ip
    - '*.lan'
    - localhost.ptlogin2.qq.com

  nameserver:
    - 223.5.5.5         # Alibaba (domestic queries)
    - 119.29.29.29      # Tencent

  fallback:             # Foreign domains use these
    - https://1.1.1.1/dns-over-https
    - https://8.8.8.8/dns-over-https

  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 240.0.0.0/4

Debugging Tips

Checking Which Rules Are Matched

Mihomo provides a REST API to see which rule each connection matches:

# View connections list (including matched rules)
curl http://127.0.0.1:9090/connections

Dashboards like Yacd or MetaCubeX make it even clearer — you can watch in real-time which node each connection uses and which rule it matches.

Testing Which Route a Specific Domain Takes

# Test using Mihomo's HTTP proxy
curl -x http://127.0.0.1:7890 https://www.google.com -I
curl -x http://127.0.0.1:7890 https://www.baidu.com -I

Further Reading:


📷 Cover image · Generated with Flux Schnell AI · Panshi.io brand style