Clash Split Tunneling Rules: GEOIP, GEOSITE & RULE-SET
Build Clash rules for direct connections in mainland China and proxy routing elsewhere with GEOIP, GEOSITE, and RULE-SET. Learn rule order, MATCH fallbacks, and how to fix common misroutes.
Check the core and rule mode first
Routing traffic inside and outside mainland China takes more than a single “direct for China” rule. Domain categories, IP geolocation, manual exceptions, and the final default route each handle a different part of the job. A practical setup handles explicit exceptions first, matches domestic domains next, uses domestic IPs as a fallback, and sends everything else to a designated policy group.
This configuration targets Clash Meta, now known as the mihomo core. Clash is a commonly used umbrella term for a family of cores and clients; it does not mean every legacy core supports the same fields. In particular, GEOSITE and geodata settings do not work across all older Clash versions. Check the core listed in your client’s About or core information page before editing the config; seeing “Clash” in the window title is not enough.
- Set the mode to Rule. Global mode does not select routes by evaluating the rules in this guide, and Direct mode is not suitable for testing split tunneling.
- Make sure a usable policy group exists. The examples below assume your config already has a group named
Overseas-Proxywith at least one working node. The name must match exactly. - Keep the original subscription config. Prefer your client’s persistent override or merge feature to add custom rules. Direct edits to generated subscription files may be lost the next time the subscription updates.
Rule order matters more than rule count
Rules are evaluated from top to bottom. Once one matches, its target policy is used; later rules do not get another vote for that connection. “More specific rules come first” is not something the core determines automatically—it is up to the config author to put them first.
rules:
- DOMAIN-SUFFIX,github.com,Overseas-Proxy
- GEOSITE,cn,DIRECT
- GEOIP,CN,DIRECT,no-resolve
- MATCH,Overseas-Proxy
In this four-rule setup, github.com and its subdomains first go to the manually specified group. Connections matching the domestic domain set go direct; connections with a destination IP identified as an address in China by the database also go direct; everything else falls through to MATCH. The first rule covers this suffix only—it does not automatically include every domain GitHub uses for static assets.
Three terms that are easy to mix up
| Rule type | What it matches | Best used for |
|---|---|---|
GEOSITE | A category in a domain-classification database | Routing by domain category, with less reliance on IP geolocation |
GEOIP | The country or region assigned to the destination IP | Catching connections not covered by the domain list |
RULE-SET | A separately defined rule provider | Maintaining your own exception list or standalone rule file |
DIRECT is a built-in direct-connection policy, while Overseas-Proxy is the policy group name used in this guide. They are different kinds of objects. A rule that targets a policy group only sends traffic to that group; you still need to check whether the group currently selects a node or DIRECT.
Prepare GEOSITE and GEOIP data
In GEOSITE,cn, cn is a category name in the database, not a country label looked up by the core in real time. Whether it exists and which domains it contains depend on the geosite.dat in use. Likewise, GEOIP,CN checks the IP database’s country assignment; it does not identify where a website’s company is registered or guarantee the server’s physical location.
The configuration below explicitly enables geodata-mode: true, so GEOIP uses geoip.dat and GEOSITE uses geosite.dat. Use your client’s existing data management method to prepare both files, then check the startup log for loading errors. If your current config uses MMDB mode, do not just flip the setting without providing the corresponding data.
- Get data files from a trusted maintainer and make sure they are compatible with your core. A correct filename does not guarantee the file uses the right format.
- If you get an error that a category does not exist, first check which category names the database contains. Do not change
cnto another category based on guesswork. - Updating the database can change which categories domains match. Keep your old config and known-good data, then retest the same set of sites after updating.
This guide does not cover automatic download URLs, so that a failed file download is not confused with a rule error. For initial troubleshooting, first make sure the local data can be read reliably; set up an update schedule afterward. This makes problems easier to isolate.
Manage manual exceptions with RULE-SET
Put manual exceptions before category-based rules. That way, if a site is classified incorrectly, you can update a small list instead of copying an entire rule database. The example uses local YAML files: no online rule-file download is required, and you can easily confirm exactly which content is being loaded.
Step 1: Define two rule providers
Merge the fields below into the top level of your existing config. If rule-providers already exists, add both entries under it; do not create a second top-level key with the same name. Relative paths are resolved from the core’s actual working directory, which may not be the directory containing the downloaded file. Sandboxed clients may also restrict which paths can be read.
mode: rule
geodata-mode: true
rule-providers:
local-direct:
type: file
behavior: classical
format: yaml
path: ./rules/local-direct.yaml
local-proxy:
type: file
behavior: classical
format: yaml
path: ./rules/local-proxy.yaml
behavior: classical means the file contains entries with rule types, such as DOMAIN-SUFFIX. Entries in the provider do not specify an outbound policy; that is set by the RULE-SET line in the main config. If you switch to behavior: domain, you must also change the file syntax—do not mix the two formats.
Step 2: Create local lists
The two lists below demonstrate how to send specified domains direct or through a proxy. example.com is a documentation example, not a recommended connectivity test site. Remove it before use and maintain the lists for your own needs.
rules/local-direct.yaml:
payload:
- DOMAIN-SUFFIX,example.com
rules/local-proxy.yaml:
payload:
- DOMAIN-SUFFIX,github.com
- DOMAIN-SUFFIX,githubusercontent.com
These two proxy exceptions only demonstrate how to configure the rules. They do not mean the services in question must always use a proxy on every network, nor do they cover every associated domain. If a page loads but its images do not, check the domains used by the failed requests rather than routing an entire CDN range through the same outbound policy.
Step 3: Order the rules in layers
Reorder your existing rules list as shown below. The example covers the IPv4 loopback and common private ranges, as well as IPv6 loopback, unique local, and link-local addresses. It is not a complete list of all special-purpose addresses.
rules:
- 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
- RULE-SET,local-direct,DIRECT
- RULE-SET,local-proxy,Overseas-Proxy
- GEOSITE,cn,DIRECT
- GEOIP,CN,DIRECT,no-resolve
- MATCH,Overseas-Proxy
Handle local addresses first to keep connections to your router or intranet services from being sent through the final proxy route. These address rules include no-resolve, so they will not actively query DNS just to resolve a domain that has no IP yet. If you rely on intranet domains, also add the actual domains to your direct list and configure a reachable internal DNS server.
If the two custom lists contain the same domain, the earlier local-direct rule wins. Keep the lists mutually exclusive where possible to avoid wondering months later why a rule is not taking effect. If your subscription includes block, app-specific, or special-service rules, reorder them to fit your needs rather than discarding them outright.
Understand the limits of no-resolve and MATCH
no-resolve does not disable DNS
GEOIP,CN,DIRECT,no-resolve means that if there is no destination IP available to check, this IP rule will not initiate a DNS lookup just for the match. Connections made directly to an IP, or those for which the core already has the actual destination IP, can still match. This parameter does not stop your browser from resolving domain names or disable the DNS module as a whole.
There is a clear trade-off: if a domain in mainland China is missing from GEOSITE,cn and no IP is available when the GEOIP rule is reached, it may fall through to MATCH and ultimately use a proxy. This is an expected limitation of this conservative setup, not proof that the core ignored GEOIP.
- Fix the domain list first: Add confirmed direct-connection domains to
local-direct. The result is clear and easy to roll back. - Allow resolution if needed: Remove
no-resolvefrom the GEOIP rule so the IP check can trigger a lookup, but also check the resolution delay and DNS route. - Do not mistake fake-IP addresses for server addresses: For example,
198.18.0.0/16may be used as a fake-IP pool. Do not use that address alone to determine where a service belongs.
MATCH is a fallback for unmatched traffic, not failover
MATCH,Overseas-Proxy provides a clear target only when none of the preceding rules match. It will not retry a direct connection if a proxy node fails. For node failover, use an appropriate group type and configure health checks correctly. Conversely, MATCH,DIRECT means “send anything unidentified direct,” which can expose unlisted domains outside mainland China to a direct connection.
This guide uses a “direct for allowlisted domains in mainland China, proxy for everything else” approach. It lets new overseas domains use the proxy by default, but cannot guarantee that every domestic service will be identified correctly. Split tunneling does not eliminate misclassification automatically; a few manual exceptions are still needed.
Verify the actual route in connection logs
A config loading successfully only shows that its syntax and references are broadly valid; it does not prove that traffic is passing through the core as expected. First confirm that your browser is using the system proxy or that TUN is correctly capturing the target app. The system proxy generally affects only apps that follow proxy settings, so it does not mean that all UDP traffic or apps with their own network stacks are covered.
- Reload and check the logs. Look for errors such as rule-file read failures, missing GEOSITE categories, or nonexistent target policies. Keep the log level at
infoinitially; temporarily switch todebugif you need more detail, then switch back after reproducing the issue. - Test a manual exception first. Visit a domain on one of your lists, then check the connection details to see whether it matched
RuleSet. Check the associated provider and the final policy chain as well. - Test domain classification next. Choose a domain that is actually included in the current database’s
cncategory. Confirm that the rule type isGeoSiteand the policy isDIRECT. - Check the fallback last. Find a connection that did not match any earlier rule, confirm that it falls through to
Match, and check which node is currently selected inOverseas-Proxy.
Close existing connections related to the test before each run, then establish a new connection. Existing TCP connections do not switch routes automatically when you edit the rule file, and browser connection reuse can make it look as if a rule change had no effect. Record the domain, destination IP, matched rule, and final route; this is more useful than a screenshot of a failed page.
How to troubleshoot common misroutes
| Symptom | Check first | What to do |
|---|---|---|
| A site in mainland China uses a proxy | Did it match Match? Is the domain in the database? | Confirm the domain, add it to local-direct, then check whether GEOIP is skipping resolution |
| A site outside mainland China goes direct | Did it match GeoIP or an earlier direct list? | Add the domain to local-proxy and make sure the rule comes before GEOSITE and GEOIP |
| RULE-SET has no effect | Provider name, path, and file format | Check the classical entry syntax and payload structure, then reload and review the error log |
| Traffic matches a proxy group but still goes direct | The group’s current selection and nested policy chain | Check whether the group has selected DIRECT and trace the final route through each nested group |
| The homepage loads but its resources fail | The separate domains used by the failed resources | Use connection logs to add the resource domains; do not expand the rule to an entire shared IP range |
| Config resets after a subscription update | Was the change made in a temporary generated file? | Move the change to the client’s persistent override feature and check the order of the merged config |
Putting domain rules before GEOIP is useful when a site in mainland China resolves to an overseas CDN: once its domain matches the direct list, a later overseas IP classification cannot override that result. Conversely, if an overseas service uses a domestic IP address, GEOIP alone may send it direct, so explicit proxy exceptions must come before the IP check.
Keep a small, stable test set: one manual direct domain, one manual proxy domain, one domain in the domestic category, and one connection that actually reaches the fallback. Change one thing at a time and retest with the same requests. Your split-tunneling setup is working when you can explain why each connection took its route; adding more rules usually will not fix ordering, DNS, or a misconfigured policy group.