Clash Rule Routing in Practice: China Direct, Overseas Proxy Config and Priority Debugging

Real rules examples explain DOMAIN-SUFFIX, GEOIP, and MATCH matching order, a minimal split-routing ruleset, and how to debug rules that aren't working.

Why split-routing matters

A config with no split-routing only has two extremes: full proxy or full direct. Full proxy slows down access to sites inside mainland China (banking, government services, some video platforms) and can even trigger risk controls; full direct is equivalent to not using a proxy at all. Rule-based routing lets Clash decide, on every connection attempt, which category the target domain or IP falls into, then choose direct, proxy, or reject. This decision is driven entirely by the rules section — the more sensible the rules, the closer the experience gets to "proxy what needs proxying, direct-connect what doesn't."

The Clash core (including the actively maintained Clash Meta / mihomo core) processes rules by matching them top to bottom, one at a time. The first match wins and its policy is applied immediately; nothing after it is evaluated. This means rule order is itself logic — reversing the order makes finely tuned later rules meaningless.

Matching order: what DOMAIN-SUFFIX, GEOIP, and MATCH each do

A typical rules section mixes several matcher types. The common ones and what they mean:

  • DOMAIN-SUFFIX: matches by domain suffix — for example, DOMAIN-SUFFIX,google.com hits www.google.com, mail.google.com, and any domain ending in that suffix.
  • DOMAIN-KEYWORD: matches when the domain contains a given keyword. Broader scope, easy to over-match, usually placed further down.
  • GEOIP: matches by the country/region the target IP belongs to — for example, GEOIP,CN,DIRECT means an IP registered to mainland China goes direct. This relies on a built-in or external GeoIP database and only resolves after DNS lookup.
  • IP-CIDR / IP-CIDR6: matches by IP range, commonly used for LAN addresses and internal subnets that should always go direct.
  • MATCH: the catch-all — no condition, fires when nothing above it matched, and must be the last line in the entire rules section.

The key point: domain-based rules (DOMAIN-SUFFIX/DOMAIN-KEYWORD) can be evaluated before DNS resolution, so they're fast; GEOIP-based rules need the IP resolved first, so they usually sit after domain rules. Putting GEOIP,CN,DIRECT first guarantees mainland IPs go direct with priority, but it also means every request has to resolve first before matching — not ideal if speed matters. Placing it after domain rules but before MATCH is the more balanced choice.

A minimal working ruleset example

Below is a minimal ruleset you can read at a glance and extend as needed, covering the four most basic cases: direct connect within mainland China, proxy for overseas traffic, direct for LAN, and a catch-all proxy fallback:

rules:
  # LAN and internal addresses go direct
  - IP-CIDR,192.168.0.0/16,DIRECT
  - IP-CIDR,10.0.0.0/8,DIRECT
  - IP-CIDR,127.0.0.0/8,DIRECT

  # Common domains that should go direct
  - DOMAIN-SUFFIX,cn,DIRECT
  - DOMAIN-SUFFIX,baidu.com,DIRECT
  - DOMAIN-SUFFIX,qq.com,DIRECT
  - DOMAIN-SUFFIX,alipay.com,DIRECT

  # Common domains that need a proxy
  - DOMAIN-SUFFIX,google.com,PROXY
  - DOMAIN-SUFFIX,youtube.com,PROXY
  - DOMAIN-SUFFIX,github.com,PROXY

  # Fallback based on IP geolocation
  - GEOIP,CN,DIRECT

  # Anything not matched above goes through the proxy
  - MATCH,PROXY

Here PROXY is a policy group name that must be defined ahead of time in the proxy-groups section, usually pointing to subscription nodes or a manually selected group; DIRECT is a built-in direct-connect policy that needs no extra definition. The order of these rules strictly follows the four cases above, arranged from "precise, low cost" to "broad, high cost" — a general principle worth following whenever you write a ruleset.

Tip: MATCH can only appear once, and must be the very last line of the entire rules section. Duplicating it, omitting it, or misplacing it will cause parsing errors or leave later rules permanently unreachable.

Using RULE-SET instead of scattered domain lists

Hand-writing a few dozen DOMAIN-SUFFIX lines works fine for personal use, but it can't cover a full list of domestic and overseas sites. In practice it's far more common to reference a rule set (RULE-SET), maintaining large domain/IP lists in an external file and keeping only a reference in the rules section:

rule-providers:
  cn-domains:
    type: http
    behavior: domain
    url: "https://example.com/rules/cn-domains.txt"
    path: ./rules/cn-domains.yaml
    interval: 86400

rules:
  - RULE-SET,cn-domains,DIRECT
  - GEOIP,CN,DIRECT
  - MATCH,PROXY

The rule set refreshes automatically at the interval set by interval (in seconds), so there's no need to manually update every domain. The behavior field determines how the rule set's contents are parsed (domain / ipcidr / classical) and must match the actual format of the rule set file — getting this wrong can cause silent load failures, which is an easy step to overlook when debugging rules that don't work.

Common debugging steps when rules don't work

When connection behavior doesn't match what the rules should produce, work through these checks in order:

  1. Confirm policy group names match exactly

    Names like PROXY or DIRECT referenced in rules must exactly match the name defined under proxy-groups, including case. A mismatch behaves differently across clients — some throw an error, others silently fall back to a default policy, which is easy to mistake for "the rule isn't working."

  2. Check whether a broader rule is intercepting traffic earlier

    If a DOMAIN-KEYWORD or GEOIP rule sits above a precise DOMAIN-SUFFIX rule, the precise rule never gets a chance to run. Temporarily moving the suspect rule to the top for testing quickly confirms whether it's an ordering issue.

  3. Verify the DNS resolution result matches expectations

    GEOIP-based rules rely on the resolved IP. If the client has fake-ip mode enabled or uses an overseas DNS server, the resolved IP may not match the real location, causing GEOIP,CN to fail silently. Check the client's connection log or rule-hit record to see which rule an actual connection matched.

  4. Check whether the rule set was fetched successfully

    With RULE-SET, if the external URL fails to load or the format fails to parse, the rule set loads empty — the reference is effectively dead, and traffic falls through to the catch-all MATCH. Checking the client's startup log or rule-set refresh status confirms this.

  5. Rule out multiple configs or profiles overriding each other

    Some clients support switching between multiple configs. If you edited a backup profile while a different one is actually active, the changes naturally won't show up. Confirming which config file path is currently active is the easiest thing to overlook, and the most common cause.

A few practical habits for writing rulesets

A ruleset isn't something you write once and never touch again. A few habits pay off long-term: precise rules first, broad rules later, to reduce mismatches; LAN and internal subnet rules always at the very top, so local services never get accidentally proxied; GEOIP,CN,DIRECT usually sits after domain rules and before MATCH, as a fallback for mainland IPs rather than the primary decision method; for domains involved in cross-border work or payments, list them explicitly for direct or proxy rather than relying entirely on GEOIP classification, since some services' IP location doesn't match where the business actually operates. The value of a ruleset grows over time — periodically reviewing the connection log and turning domains that keep falling through to MATCH into explicit rules will make routing progressively more accurate.

Get the Clash Client

Before setting up rule-based routing, install the client for your platform and import your subscription first.

Download Client