Clash Custom Rules: DOMAIN-SUFFIX, GEOIP, and MATCH Order
Learn common Clash rule syntax, how rules are evaluated from top to bottom with the first match taking priority, and how to use rule-providers and resolve conflicts.
Check the rule mode first, then adjust the order
Put specific exceptions first, broader rules later, and use MATCH last to catch any remaining connections. Clash checks the regular rule list from top to bottom and applies the policy for the first matching rule. It does not keep searching for a “more specific” rule. A more specific rule does not automatically get higher priority.
Before making changes, confirm that the client is in Rule mode. Global mode does not use this regular routing list to choose an outbound route, and Direct mode cannot be used to verify proxy rules. The label may vary by client; select “Rule” in the mode switcher and confirm that the active configuration contains mode: rule.
Understand rules, policies, and the actual outbound route
- Rule: Checks whether a connection meets a condition, such as a domain ending in
example.com. - Policy: Determines how a connection is handled, such as by the built-in
DIRECTorREJECTpolicies, or a policy group namedPROXY. - Actual outbound route: The node or direct option currently selected in a policy group. Matching
PROXYdoes not necessarily mean traffic goes through a remote node; check the selection within the group.
Here, PROXY is a custom group name, not a built-in policy included in every configuration. If your subscription names the group “Node Selection,” use that exact name in the rule. A name mismatch, different capitalization, or a missing group can prevent the configuration from loading.
Know the difference between DOMAIN, DOMAIN-SUFFIX, and IP rules
Choose a rule type based on the information you want to match. Domain rules work well for routing websites and services; IP rules are useful for fixed addresses, local networks, and IP geolocation. The usual format is TYPE,match value,policy. MATCH has no match value, so it uses just two fields.
| Type | Example rule | What it matches |
|---|---|---|
| DOMAIN | DOMAIN,api.example.com,DIRECT |
Matches this exact domain only |
| DOMAIN-SUFFIX | DOMAIN-SUFFIX,example.com,PROXY |
Matches the root domain and its subdomains |
| DOMAIN-KEYWORD | DOMAIN-KEYWORD,example,PROXY |
Matches domains containing this string |
| IP-CIDR | IP-CIDR,192.168.0.0/16,DIRECT,no-resolve |
Matches the specified IPv4 range |
| GEOIP | GEOIP,CN,DIRECT |
Uses IP data to determine whether the address is in CN |
| MATCH | MATCH,PROXY |
Catches connections not matched by earlier rules |
Use only the hostname in the domain field
Write DOMAIN-SUFFIX,example.com,PROXY, not https://example.com/path. Do not include a protocol, path, query string, or port, and do not add *.example.com. The suffix rule already covers example.com and www.example.com; it will not match notexample.com just because the strings look similar.
DOMAIN-KEYWORD has a broader scope. The keyword example may match domains unrelated to the site you want to route. Use it only when substring matching is actually needed; for website routing, prefer an exact domain or domain suffix.
The difference between IP-CIDR and GEOIP
IP-CIDR checks whether an address falls within a subnet; GEOIP relies on the geolocation data loaded by the core. GEOIP checks only the location associated with the destination IP, not the page content, domain registration location, or visitor’s location. A Chinese-language site using an overseas CDN may not match GEOIP,CN.
For IPv6 ranges, use the corresponding IP-CIDR6 rule, such as IP-CIDR6,fc00::/7,DIRECT,no-resolve. Adding an IPv4 exception alone does not mean IPv6 connections to the same service will use the same route.
Order specific exceptions and fallback rules by first match
Consider this specific conflict: route api.example.com directly, while proxying other example.com subdomains. The exact-domain exception must come before the suffix rule.
rules:
- DOMAIN,api.example.com,DIRECT
- DOMAIN-SUFFIX,example.com,PROXY
- GEOIP,CN,DIRECT
- MATCH,PROXY
- For
api.example.com, the first rule matches and selectsDIRECT. - For
www.example.com, the first rule does not match, so the second one does and routes it toPROXY. - For other domains, continue checking the IP location; if it matches CN, route directly.
- If none of the earlier rules match, the final
MATCHrule routes the connection toPROXY.
If you swap the first two rules, the suffix rule catches api.example.com first, and the exact-domain rule never runs. Putting MATCH first is even more direct: none of the regular rules below it will get a chance to match.
Use a loadable minimal configuration to verify names
This configuration structure demonstrates how the parts fit together and does not include any remote proxy nodes. To make PROXY a valid reference, the example defines a selection group with that name and temporarily adds only DIRECT to it. So even when a rule matches this group, the final route is still direct. In real use, keep the nodes and policy groups already present in your subscription.
mixed-port: 7890
mode: rule
log-level: info
proxy-groups:
- name: PROXY
type: select
proxies:
- DIRECT
rules:
- DOMAIN,api.example.com,DIRECT
- DOMAIN-SUFFIX,example.com,PROXY
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- GEOIP,CN,DIRECT
- MATCH,PROXY
mixed-port: 7890 is simply the local mixed HTTP/SOCKS proxy port in this example, not a rule-matching condition. If your client uses a different port, test against the actual listening port. When editing an existing configuration, do not add a second top-level rules: key; modify the existing list or use the client’s merge feature.
How GEOIP, DNS, and no-resolve work together
Let domain rules handle clear matches first, then consider whether IP-based checks are needed. If a connection has a domain but no destination IP yet, an IP rule may trigger DNS resolution. Placing common domain exceptions before GEOIP makes your routing intent clearer and can avoid unnecessary IP checks.
no-resolve does not disable DNS
Append no-resolve to an IP rule that supports it to prevent that rule from actively resolving a domain just to check for a match. If the connection already has a usable IP, the rule can still evaluate it. This does not disable system DNS or guarantee that the connection will never be resolved later in processing.
rules:
- DOMAIN-SUFFIX,example.com,PROXY
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- GEOIP,CN,DIRECT,no-resolve
- MATCH,PROXY
This configuration may behave differently from one without no-resolve. If no destination IP is available, GEOIP with this option may not match, leaving the request to fall through to MATCH. Do not add this option mechanically to every IP rule just to reduce DNS lookups.
Domain rules cannot match a domain the core never receives
An app may connect directly to an IP address or perform its own encrypted DNS resolution. In that case, the connection record may not include the original domain. TUN captures network traffic, but that does not guarantee every request’s domain will be preserved. A correctly configured Fake-IP mapping or sniffing can help recover domain information in supported cases, but not every protocol can be assumed to support it.
- First, check the hostname and destination IP in the connection details to see what information the core actually has.
- Next, check that DNS requests are reaching the core as expected, rather than taking separate resolution paths through the app and system.
- Finally, adjust DNS or sniffing settings. Do not try to fix missing domain information by continually adding more domain rules.
Split rule files with rule-providers
Move rules that you maintain repeatedly into a separate file, then reference them with RULE-SET. rule-providers declares where the rules come from; the reference position in rules determines their priority. Declaring a provider without referencing it does not make its rules part of routing.
Declare a local rule set in the main configuration
The example below uses a local file provider supported by mihomo. The file path is resolved relative to the core’s working directory. Clients may use their own configuration directory, so confirm the core’s working directory before creating rules/local-direct.yaml.
rule-providers:
local-direct:
type: file
behavior: classical
format: yaml
path: ./rules/local-direct.yaml
rules:
- DOMAIN,api.example.com,PROXY
- RULE-SET,local-direct,DIRECT
- GEOIP,CN,DIRECT
- MATCH,PROXY
Put match conditions only in the rule file
Save the following content to the path above. The classical format supports rule conditions such as domains and subnets. Do not include a final policy on each line; the main configuration already specifies it in RULE-SET,local-direct,DIRECT.
payload:
- DOMAIN-SUFFIX,example.com
- DOMAIN,intranet.example.net
- IP-CIDR,192.168.0.0/16,no-resolve
With this ordering, api.example.com matches the exact rule in the main configuration first and is routed to PROXY; other connections that match the rule set go to DIRECT. If you move RULE-SET to the top, its suffix condition catches the API domain first.
The content formats for behavior: domain, ipcidr, and classical differ. Changing the declaration while keeping incompatible file contents will not work. Before using someone else’s rule set, check its format, path, and core compatibility, then reload and review the logs. Remote providers also depend on download and update status; if a download fails, troubleshoot the provider rather than assuming the rule order is wrong.
Find rule conflicts in connection logs
Start a new connection to the same destination and note three things: the matched rule, the policy chain, and the actual outbound route. Do not rely only on whether the page loads to judge if a rule works; caching, existing connections, and policy group selections can make the result appear unchanged.
- Confirm traffic capture: Open the client’s connection list and make a request. If no connection appears, check the system proxy, app proxy, or TUN capture before changing rules.
- Confirm the mode: Make sure the client is in Rule mode and that the configuration you edited is active.
- Find the first matching rule: Check the rule type and match value in the connection details or logs, then locate it in the main configuration or rule set.
- Check the policy chain: Confirm the current selection within the group. For example, if the rule matches
PROXYbut the group selectsDIRECT, the actual route is still direct. - Start a new connection: Save and reload the configuration, close any existing connections to the test destination, and try again. Existing connections usually do not switch routes automatically when rules change.
Test through a specific local port
If the mixed proxy listens on 127.0.0.1:7890, use the command below to send a request through that port. Choose a real service you want to test; the reserved example domain here illustrates the command format only and says nothing about your proxy’s performance.
curl --proxy http://127.0.0.1:7890 --connect-timeout 10 --max-time 20 -I https://example.com
To test over SOCKS and let the proxy resolve the domain, use socks5h. This may provide different domain information than a test that resolves the domain locally, so note the protocol used when comparing results.
curl --proxy socks5h://127.0.0.1:7890 --connect-timeout 10 --max-time 20 -I https://example.com
| Symptom | Check first | What to do |
|---|---|---|
| Every connection matches MATCH | The position of MATCH, whether the destination has a domain, and whether earlier rules loaded | Move the fallback to the end; check the active configuration and connection metadata |
| Exact-domain exception has no effect | Earlier suffix, keyword, or RULE-SET rules | Move the specific exception ahead of any rule that covers it |
| Matches a proxy group but still routes directly | The group’s current selection and nested policy chain | Select the desired outbound route, then start a new connection |
| Configuration reload fails | YAML indentation, policy names, rule set path, and format | Use the error log to locate the field; restore a working configuration, then change one thing at a time |
Keep custom rules after subscription updates
Prefer persistent overrides, merge options, or custom rule features explicitly supported by the client. Direct edits to a configuration generated from a downloaded subscription may be overwritten the next time it updates. Menu names and workflows vary by client; first check whether the feature edits the source configuration, generates a configuration, or changes only the current runtime configuration.
Check the active configuration, not just the editor
- Check where rules are inserted: “Prepend rules” is suitable for specific exceptions. Rules appended after
MATCHwill never get a chance to match. - Check how rule arrays are handled: Some merge methods append to
rules; others replace the entire list. Test the behavior with a single rule first. - Check that names stay consistent: If a subscription update changes a policy group name, update your local rules too to avoid referencing a nonexistent policy.
- Check provider status: The main configuration reference, provider file, and path must all be valid; any one of them being missing or invalid can prevent loading.
Change one type of rule at a time and keep a working configuration from before and after each change. Test one exact domain first, then expand to suffix rules or a rule set. This makes it easier to tell whether a rule did not match, selected the wrong policy, or routed through an unavailable outbound connection—and to recheck after subscription updates.