Clash Rule Routing: Pair GEOIP with DOMAIN-SUFFIX for mainland China and international traffic
See real Clash rules for routing traffic from mainland China directly and other traffic through a proxy, with rule order, MATCH fallbacks, and rule-provider maintenance.
First, confirm traffic reaches the core and the mode is set to Rule
Traffic routing by region is not determined by node names in the app. Instead, each connection that reaches the core is routed based on conditions such as its domain or destination IP. This guide uses a simple approach: direct connections for explicitly listed domains first, direct connections for mainland China IPs next, and a proxy group for everything else. These regional labels are shorthand for routing policies; they do not reliably identify a website’s place of registration, operator, or content origin.
The original Clash for Windows project is no longer maintained. If you’re keeping an older setup, its basic rule syntax may still be useful. For a new configuration, first check maintenance status and core support in Choosing a Client. The basic rules below work with common Clash configurations; the rule-set example is for mihomo and does not assume that legacy CFW supports modern core features.
- In Clash for Windows, enable the system proxy under General → System Proxy to route apps that follow Windows proxy settings through the client. Apps that ignore the system proxy need to be configured separately or routed through a properly configured TUN interface.
- Go to Proxies → Rule and confirm the mode is set to Rule. Global sends connections through the global policy, while Direct connects without a proxy; neither mode is suitable for testing these rules.
- Under Profiles, check which configuration is active and whether it already defines a proxy policy group. This guide uses
PROXYas the group name; replace it with the exact name in your configuration.
DOMAIN-SUFFIX, GEOIP, and MATCH each have a distinct role
Clash generally evaluates rules from top to bottom and stops at the first match that determines an outbound route. The rule list does not automatically choose the “most specific” match. Put a broad rule first, and a more specific exception farther down may never run.
| Syntax | Matches | Notes |
|---|---|---|
DOMAIN,example.com,DIRECT | Exact domain | Does not match www.example.com. |
DOMAIN-SUFFIX,example.com,DIRECT | A domain and all its subdomains | Matches example.com and a.example.com, but not notexample.com. |
GEOIP,CN,DIRECT | The GeoIP database’s classification of the destination IP | Depends on local data; does not mean the website belongs to a Chinese company. |
MATCH,PROXY | Connections without an outbound route determined by an earlier rule | Put it last; PROXY must be an existing proxy or policy group. |
Use domain names, not URLs
After DOMAIN-SUFFIX, enter a domain only—no https://, port, or path. For example, to connect directly to Alipay-related domains, use DOMAIN-SUFFIX,alipay.com,DIRECT, not a full URL. This rule type does not inspect URL paths such as /login or /video.
A domain suffix is not a geographic boundary. Don’t treat every .com site as international or rely on .cn to determine where a server is located. Explicitly route domains for services you use, then use IP geolocation for other destinations. This is usually easier to inspect and maintain.
Basic configuration: exceptions first, GEOIP next, and a fallback last
This is a snippet for your main configuration, not a complete subscription with proxy nodes. Back up your current configuration and confirm it has a proxy group named PROXY before using this example. Keep your existing nodes, DNS, and port settings when merging it. If a top-level rules: list already exists, edit that list rather than adding a second key with the same name.
mode: rule
rules:
# Local machine and common private IPv4 ranges
- DOMAIN,localhost,DIRECT
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,10.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
# Local machine and private IPv6 addresses
- IP-CIDR6,::1/128,DIRECT,no-resolve
- IP-CIDR6,fc00::/7,DIRECT,no-resolve
- IP-CIDR6,fe80::/10,DIRECT,no-resolve
# Add explicit domain policies for your services as needed
- DOMAIN-SUFFIX,baidu.com,DIRECT
- DOMAIN-SUFFIX,qq.com,DIRECT
- DOMAIN-SUFFIX,alipay.com,DIRECT
- DOMAIN-SUFFIX,wikipedia.org,PROXY
# Direct-connect mainland China IPs not handled by domain rules
- GEOIP,CN,DIRECT
# Send all other connections to the existing proxy group
- MATCH,PROXY
This order sends local network traffic direct first, then handles explicit domain exceptions. GEOIP,CN,DIRECT provides a broader IP-based match, and MATCH catches whatever remains. The example domains illustrate the syntax; they are not a complete list of services in mainland China. An app may also use separate domains for images, sign-in, payments, and updates.
Why not put GEOIP before all domain rules?
Suppose a service domain must always use a proxy, but its current IP address is classified as CN by the GeoIP data. If the GEOIP direct rule comes first, the later proxy rule for that domain may never run. Put explicit service-specific policies first, then use geolocation as a broader fallback to preserve exceptions.
Your local network rules should match your actual network. This example includes 172.16.0.0/12, not the entire 172.0.0.0/8 range. Don’t route a whole block directly just to save a few lines if it may include public IPs. These rules only choose an outbound route; they do not fix TUN routing, network adapter priority, or firewall blocks.
no-resolve after GEOIP: one less lookup can also mean one fewer match
When troubleshooting routing, you’ll often see two variants: GEOIP,CN,DIRECT and GEOIP,CN,DIRECT,no-resolve. The difference is not the geolocation database; it’s whether the core may resolve a domain to determine the destination IP when evaluating the rule.
- Without no-resolve: For a domain connection that still needs a destination IP to be evaluated, the core can resolve the domain and check the resulting IP against GeoIP data. The basic example above uses this form to cover services in mainland China that aren’t listed in the domain rules.
- With no-resolve: This rule will not trigger a DNS lookup just to evaluate itself. If the current connection context has no usable destination IP, the connection may fall through to the later MATCH rule.
- If an IP is already available: IP-based rules with no-resolve may still match direct IP connections or connections where the core already has an address available in the current context. Check the connection details rather than inferring the result from the configuration alone.
So don’t add no-resolve to GEOIP and expect it to catch every unlisted domain from mainland China. To minimize lookups triggered for routing, maintain enough domain rules up front and accept that some unknown domains will fall through to the proxy rule.
A fake IP is not a website’s real address
With fake-IP enabled, an app may see a mapped address in the 198.18.0.0/16 range. This virtual address lets the core associate connections with domains; it is not the website’s real location. Don’t add the entire fake-IP pool to your direct rules as a way to “fix GEOIP.” Instead, check the domain recovered by the core, the actual DNS results, and the matched rule. DNS settings should also match your core and client versions. See Configuration Reference.
rule-providers: keep frequently used domain rules in a maintainable file
Once your rules grow from a dozen entries to hundreds, keeping every domain in the main configuration makes them harder to review. Use rule-providers to declare a rule source, then reference it in the main rule list with RULE-SET. The example uses a local rule file supported by mihomo, keeping remote downloads and scheduled updates out of the basic routing troubleshooting process.
Step 1: Declare and reference the rule set in the main configuration
Move the domains you want to maintain into a rule set, then use the declarations and rules below to replace the corresponding sections of your main configuration. local-direct is a custom rule-set name; the reference must match it exactly. Keep your existing local network rules before the rule set.
rule-providers:
local-direct:
type: file
behavior: classical
path: ./rules/local-direct.yaml
rules:
- DOMAIN,localhost,DIRECT
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,10.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
- IP-CIDR6,::1/128,DIRECT,no-resolve
- IP-CIDR6,fc00::/7,DIRECT,no-resolve
- IP-CIDR6,fe80::/10,DIRECT,no-resolve
- DOMAIN-SUFFIX,wikipedia.org,PROXY
- RULE-SET,local-direct,DIRECT
- GEOIP,CN,DIRECT
- MATCH,PROXY
Step 2: Create the rule-set file
Save the following content to rules/local-direct.yaml under the core’s working directory. Relative paths are usually resolved from that directory, not the folder containing your downloaded subscription. Check the client logs and actual data directory to confirm. mihomo restricts file access, so place the file in an allowed data directory whenever possible.
payload:
- DOMAIN-SUFFIX,baidu.com
- DOMAIN-SUFFIX,qq.com
- DOMAIN-SUFFIX,alipay.com
Here, behavior: classical means each entry uses a rule type. Notice that the entries do not end with ,DIRECT: the outbound route is specified by RULE-SET,local-direct,DIRECT in the main configuration. If you switch to behavior: domain, you must also change the entry format; changing behavior alone while keeping the original entries will not work.
A local file rule set does not fetch new content on a remote subscription’s update schedule. After editing the file, use the client’s configuration or rule-set reload option and check the logs to confirm it was read successfully. If you need an HTTP rule set, configure a trusted source, cache path, and update interval. For example, interval: 86400 is measured in seconds and means one day, but the source format must still match the selected behavior.
Subscription updates and rule maintenance: check what can overwrite your changes
Direct edits to a configuration generated by the client are often overwritten the next time it updates. A safer approach is to keep the original subscription as the source of proxy nodes and maintain your rules in a client-supported override, merge, or extension layer. Merge behavior varies: some clients replace the entire rules section, while others support prepending rules. A successful save does not guarantee the order is correct.
- Back up first: Save the original configuration and any working rule-set files, and note the name of the active configuration.
- Check the final configuration: Confirm that
mode: rule, the proxy group name, rule order, and rule-provider declarations are all present in the configuration actually being used. - Update the subscription once: Check everything again after updating. Don’t wait until the next day to discover your custom rules have disappeared.
- Change one thing at a time: Test domain rules first, add GEOIP next, and split out rule sets last. If something breaks, it will be easier to identify which change caused it.
GeoIP data and domain rules require separate maintenance. Updating GeoIP data won’t add domains for newly introduced app services, and adding domain rules won’t correct outdated IP classifications. Database names, download methods, and update options depend on the core. Don’t copy another client’s filenames directly into the CFW directory.
Verify routing by checking matched rules, not by whether a webpage loads
After saving the configuration, establish a new test connection. Existing long-lived connections usually won’t switch routes automatically when rules change, and browser connection reuse can make old results persist. Close the relevant connection and retry, then open the client’s Connections page to check the destination domain, matched rule, and proxy chain. Field names vary slightly between clients.
| Test case | Expected result with this example configuration | Check these first if the result differs |
|---|---|---|
Visit www.baidu.com | Matches a domain rule or local-direct; outbound route is DIRECT | Domain spelling, whether the rule set loaded, and whether an earlier blocking rule matched. |
Visit www.wikipedia.org | Matches a domain rule and enters the PROXY policy group | Check whether the group currently selects a proxy node rather than DIRECT. |
Visit your router’s actual address, such as 192.168.1.1 | Should match a local network direct rule if the connection reaches the core | If there’s no connection entry, the system proxy’s bypass list may have allowed it through directly. |
| Visit a public IP not listed in your domain rules | Evaluated by GEOIP; falls through to MATCH if there’s no match | The destination IP returned by DNS, GeoIP data, and whether no-resolve is present. |
Three common misreadings
- Assuming PROXY means a proxy node is in use: PROXY is only a group name. If the group selects DIRECT, the connection still goes direct. Check the full proxy chain.
- Assuming every resource follows the same route because the page loads: The main page, images, and sign-in APIs may connect to different domains. Check each relevant connection separately.
- Assuming rules are broken when there’s no connection entry: The app may never have reached the core. Confirm that the system proxy or TUN is capturing its traffic before troubleshooting rule matches.
For a domain routed incorrectly, investigate in this order: did the connection reach the core, what mode is running, what domain and IP were used, which rule matched, and what was the final outbound route? This is usually more effective than repeatedly switching nodes. Once the basic setup is stable, add service domains and rule sets gradually. Don’t combine lists from unknown sources with overlapping priorities just to create a rule table that looks complete.