Clash Rule-Based Routing Explained: Direct Connect for China, Proxy for Overseas Sites

A practical guide to combining DOMAIN-SUFFIX, GEOIP, and RULE-SET for split routing, how Clash matches rules top-to-bottom, and why a missing MATCH fallback or wrong rule order causes traffic to slip through.

B-01How Routing Works: Rules, Proxy Groups, and Match Order

At its core, Clash's rule-based routing is just a checklist evaluated top to bottom. The rules field in your config is an array, and every line is a standalone rule written as rule-type,match-value,policy-name. When a connection hits the Clash core, it walks the array from the first line to the last, and as soon as one rule matches, the core applies that rule's policy (direct, proxy, or reject) immediately and stops checking the rest. This "first match wins" behavior is the single most important thing to understand about routing config, and it's also the key to tracking down why a rule isn't taking effect later on.

The policy field doesn't point to a specific node — it points to a proxy group name, such as DIRECT (built into the core), REJECT (also built in), or a custom group you defined under proxy-groups, like Overseas Proxy. The proxy group itself decides which node actually handles the traffic; the rule layer only decides "which route to take," not "which car is on that route." This separation means switching nodes or tweaking latency-based selection only requires editing the proxy group, never the rules themselves.

B-02The Standard Setup: Direct for China, Proxy for Overseas

Direct-for-China, proxy-for-overseas is the most common routing setup. The idea is straightforward: pick out domains and IP ranges that clearly belong to mainland China and send them direct, pick out domains that are clearly overseas or need a proxy and route those through your proxy group, then add one fallback rule at the end to catch everything else — usually also sent to the proxy group — so nothing slips through unhandled.

In practice, three rule types do most of the work:

  • DOMAIN-SUFFIX: matches by domain suffix, ideal for well-known sites. For example, DOMAIN-SUFFIX,google.com,Overseas Proxy matches google.com and every subdomain under it.
  • GEOIP: matches by the geographic location of the destination IP, useful for traffic that doesn't follow a predictable domain pattern but has a clear server location. For example, GEOIP,CN,DIRECT sends traffic direct whenever the destination IP is registered in mainland China.
  • RULE-SET: references a pre-built rule list (local or remote) that bundles thousands of domain or IP rules into a single reference, so your main config file doesn't turn into an unreadable wall of entries.

A bare-bones direct-for-China, proxy-for-overseas rule block looks something like this:

rules:
  - DOMAIN-SUFFIX,cn,DIRECT
  - DOMAIN-SUFFIX,baidu.com,DIRECT
  - DOMAIN-SUFFIX,qq.com,DIRECT
  - DOMAIN-SUFFIX,google.com,Overseas Proxy
  - DOMAIN-SUFFIX,youtube.com,Overseas Proxy
  - DOMAIN-SUFFIX,github.com,Overseas Proxy
  - GEOIP,CN,DIRECT
  - MATCH,Overseas Proxy

The logic here is simple: handle a few domains that clearly need direct or proxy treatment first, catch everything whose destination IP lands in mainland China with GEOIP,CN,DIRECT, then send whatever's left to the proxy group via MATCH,Overseas Proxy. In real-world configs, those hand-written DOMAIN-SUFFIX lines usually get swapped out for a RULE-SET reference, since manually maintaining dozens of domain entries is far more work than just pointing to a rule list that updates itself.

B-03Referencing a Rule List with RULE-SET

RULE-SET works in two steps: first declare the rule list's name, source, and refresh interval under rule-providers, then reference it in rules with RULE-SET,rule-list-name,policy-name. For example:

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

rules:
  - RULE-SET,cn-domain,DIRECT
  - RULE-SET,proxy-domain,Overseas Proxy
  - GEOIP,CN,DIRECT
  - MATCH,Overseas Proxy

The behavior field has to match the actual content of the rule list file. There are three common values: domain for a plain list of domains, ipcidr for a list of IP ranges, and classical for mixed rule lines that already include their own type prefix on each line. Getting behavior wrong is one of the most common reasons a rule list silently does nothing — the core parses the file based on whatever behavior you declared, and a mismatch effectively turns the rule list into an empty file without throwing an obvious error.

NOTE Once downloaded, a rule list gets cached to the local file specified by path, and interval controls how many seconds until the next auto-refresh. If you suspect a rule list hasn't picked up the latest version, check the modified time on the local cache file first before deciding whether to delete it and force a re-download.

B-04Why Rule Order Matters: A Real-World Failure Case

Rule order isn't a formatting preference — it's a logical structure that directly determines the outcome of your routing. Take a look at this rule block, which looks fine but breaks in practice:

rules:
  - GEOIP,CN,DIRECT
  - DOMAIN-SUFFIX,google.com,Overseas Proxy
  - MATCH,Overseas Proxy

This config puts GEOIP,CN,DIRECT at the very top. The problem is that some overseas sites distributed via CDN happen to have an access node whose IP lands on a mainland China CDN edge, and conversely, plenty of mainland China services run accelerator nodes overseas too. GEOIP checks where the connection actually terminates, not who owns the site. If GEOIP,CN,DIRECT comes before the DOMAIN-SUFFIX rule, a request to google.com that happens to resolve to an IP flagged as mainland China in the GEOIP database gets caught by the direct rule before it ever reaches the DOMAIN-SUFFIX rule further down — sending it direct, causing a failed connection or DNS tampering issues.

The correct ordering principle is: the more specific a rule is, the higher up it should sit, with broad fallback checks pushed toward the bottom. Domain-based rules are generally more reliable than GEOIP because a domain is a fixed identity that doesn't shift with CDN routing; GEOIP works best placed after domain rules, catching the leftover traffic that isn't covered by any domain rule but can be reasonably judged by IP location. Putting DOMAIN-SUFFIX/RULE-SET first, GEOIP in the middle, and MATCH last in the earlier example is exactly this principle in action.

B-05The MATCH Fallback Rule: Mandatory, and Always Last

MATCH is a special rule that doesn't need a match value — it means "send everything that didn't hit any earlier rule to this policy." It has to be the last line in your rule list, or you'll run into two problems: skip MATCH entirely, and traffic that doesn't match anything falls back to the core's default behavior (which varies between clients — some go direct, some get rejected — so it's unpredictable). Put MATCH anywhere but last, and every rule below it becomes dead code, since MATCH catches all traffic by definition.

  1. Check that the last line in your rule file is MATCH,policy-name.
  2. Make sure no rule lines come after MATCH — if there are, delete them or move them above MATCH.
  3. Confirm the policy group MATCH points to actually exists and works. Point it at your overseas proxy group rather than a single node, so the fallback doesn't break if that one node goes down.

B-06Common Mistakes and a Troubleshooting Checklist

When a rule doesn't work or the routing result doesn't match what you expected, the cause almost always falls into one of these categories — checking them in order usually finds the problem fast:

SymptomLikely CauseHow to Check
A site that should go through the proxy is going direct insteadDOMAIN-SUFFIX rule is placed after GEOIP, or the rule list's behavior is declared incorrectlyReorder the rules, and check whether the rule list's cache file is empty
A site that should go direct is going through the proxy insteadA broader rule is matching first — for example, a DOMAIN-KEYWORD with too wide a match rangeMove the more specific rule above the broad one, and narrow or remove the overly broad keyword rule
A newly added rule has no effect at allThe rule is written after MATCH, so it's never reachedConfirm MATCH is the last line, and insert new rules above it
Rule list was updated but results still look outdatedThe local cache hasn't expired yet, or interval is set too longDelete the local cache file and restart the core, or shorten the interval
Routing has stopped working entirelyA proxy group's name doesn't exactly match the name referenced in rulesCompare the name field under proxy-groups against the policy names used in rules, line by line

A mismatched proxy group name is the easiest mistake to miss, because most clients don't throw a clear error when a policy name doesn't exist — they just silently treat the rule as invalid. The symptom looks like "the config seems fine, but routing isn't working." Get in the habit of testing a specific URL right after changing a rule — it's a lot faster than troubleshooting after the fact.

B-07Verifying Your Routing Is Actually Working

Don't just eyeball your rules and assume they're working — verify them one by one with the following approach:

  • Check the client's connection log or rule-hit history after visiting a target site to see exactly which rule matched and which proxy group handled the request. Most GUI clients show this in a "Logs" or "Connections" panel.
  • Test a few representative domains for both mainland China sites and overseas sites separately — don't draw conclusions from a single site, since some sites have unusual CDN setups of their own.
  • For configs relying on RULE-SET, confirm the rule list downloaded successfully and the local cache isn't an empty file before trusting the results.
Tip Keep your rule file organized with clear section comments splitting it into "Direct for China," "Proxy for Overseas," and "Fallback" blocks. That way, when something breaks, you can jump straight to the relevant section instead of reading through every line from top to bottom.

Ready to Set This Up: Download Clash

Once you've got the rule logic down, pair it with a GUI client's log panel to verify routing results — debugging goes a lot faster that way.

Download Clash