· Rules & Routing · 9 min read

Shadowrocket Rule syntax: what DOMAIN, DOMAIN-SUFFIX, GEOIP, and FINAL match

Learn what DOMAIN, DOMAIN-SUFFIX, DOMAIN-KEYWORD, GEOIP, IP-CIDR, and FINAL match, how to format rules, and how top-to-bottom matching works, with examples.

At a glance

Shadowrocket rule-based routing requires Config to be selected under Global Routing. This guide is for users with their own service connection details who are preparing to edit a configuration: identify the rule fields, distinguish domain matching from IP matching, then verify results in order. Example domains and addresses illustrate syntax only; they are not connection details. Keep a copy of your current configuration before making changes.

1. When rules apply and how they’re matched

In short, rules are checked from top to bottom in the order they appear in the configuration. Once a matching rule applies, its policy is used; a later, more specific rule won’t be selected automatically. Put exceptions first, broader matches later, and use FINAL to catch remaining requests. Before editing, confirm which configuration is active so your changes apply where intended.

Select Config under Home → Global Routing to route traffic using the current configuration. Proxy and Direct are global routing modes; they can’t be used to test the rule order in these examples. Scene applies routing settings for a specific scene, so check that scene’s routing as well. When testing a single rule file, select Config to avoid mistaking the effects of a routing mode for a syntax issue.

Request sent Target identified Rules checked in order Policy selected Connection established

This flow describes how rules determine a policy; it doesn’t mean every request must trigger a DNS lookup first. Domain rules use a known target domain, while IP rules use the target address. Whether the domain is available, needs to be resolved, and how DNS is configured all affect which information can be matched. A PROXY match means the proxy policy was selected, not that the connection will necessarily succeed.

2. Rule format: keyword, condition, and policy

Rule fields are commonly separated by commas. DOMAIN, DOMAIN-SUFFIX, DOMAIN-KEYWORD, GEOIP, and IP-CIDR each require a match condition and a policy; FINAL takes a policy only. Put rules in the [Rule] section of the configuration, not in [General] or [Host].

[Rule]
DOMAIN,login.example.com,DIRECT
DOMAIN-SUFFIX,example.com,PROXY
DOMAIN-KEYWORD,example,PROXY
IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
GEOIP,CN,DIRECT
FINAL,DIRECT

In this configuration, login.example.com is an exception listed first, while the rest of the example.com domain space goes through PROXY. The keyword rule has a broader match and is included only to illustrate its format; you don’t need to use every rule type in a real configuration. PROXY and DIRECT are policies, not protocol names. Check connection parameters for protocols such as Shadowsocks, VMess, VLESS, Trojan, Hysteria2, and WireGuard in your existing connection configuration—not in a rule’s policy field.

Include only the condition the rule needs. For a domain rule, enter the domain without https://, a path, query parameters, or :443. For example, the domain condition for https://example.com/account is example.com. These six rule types can’t distinguish pages on the same site by URL path.

3. DOMAIN, DOMAIN-SUFFIX, and DOMAIN-KEYWORD

DOMAIN matches one exact, complete domain. DOMAIN-SUFFIX matches the specified domain and its subdomains. DOMAIN-KEYWORD checks whether a domain contains a given string. These rules have different match scopes; they don’t all simply “contain example.” In particular, DOMAIN-SUFFIX respects domain boundaries, while DOMAIN-KEYWORD doesn’t match on suffix boundaries.

Rule conditionMatchesDoes not match
DOMAIN,example.comexample.comwww.example.com
DOMAIN-SUFFIX,example.comexample.com、api.example.comnotexample.com、example.com.other.test
DOMAIN-KEYWORD,exampleexample.com、myexample.testsample.test

Use DOMAIN for a single host. Use DOMAIN-SUFFIX to cover a root domain and its subdomains at any level. DOMAIN-KEYWORD is useful when you specifically need a string-based match, but it may also catch unrelated domains, so don’t replace a suffix rule just to save a few lines. For DOMAIN-SUFFIX, write example.com, not *.example.com.

[Rule]
DOMAIN,api.example.com,DIRECT
DOMAIN-SUFFIX,example.com,PROXY
FINAL,DIRECT

In this example, api.example.com matches DOMAIN first and uses DIRECT; www.example.com matches the second line and uses PROXY. If you swap the first two lines, the suffix rule will match api.example.com first, so the exact-domain exception won’t apply. A webpage may also load images, login pages, or API requests from separate domains. Check those requests individually rather than assuming the address bar’s domain represents all page traffic.

4. GEOIP and IP-CIDR: match by destination IP

GEOIP matches the destination IP against the geographic database used by the app, for example GEOIP,CN,DIRECT. CN is a country code; it doesn’t refer to a domain suffix or the region its content is associated with. The database’s result isn’t real-time proof of physical location, so a page displaying Chinese doesn’t mean it will match CN.

IP-CIDR checks whether the destination IPv4 address falls within a specified network range. 192.168.0.0/16 covers addresses from 192.168.0.0 to 192.168.255.255; /32 represents a single IPv4 address. The addresses below illustrate syntax only and aren’t server address recommendations.

IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
IP-CIDR,203.0.113.7/32,PROXY,no-resolve
GEOIP,CN,DIRECT
FINAL,PROXY

The final example uses FINAL,PROXY, unlike the earlier FINAL,DIRECT: it sends unmatched requests through the proxy. Choose a fallback policy based on your routing goals. When testing, record the request domain, destination address, and final policy so a different DNS response isn’t mistaken for an incorrect CIDR range.

5. FINAL fallback and configuration checks

FINAL matches any remaining request that reaches it, so put it at the end of the rules. It isn’t an automatic setting with the lowest default priority; it’s a rule in the list, and if it appears earlier, later rules won’t get a chance to match. To proxy only specified domains, use domain rules followed by FINAL,DIRECT. To proxy all other requests as well, use FINAL,PROXY.

  1. Back up the configuration

    Open Config and confirm which file is active, then save a copy before making changes. Note the existing [Rule] order so you don’t lose existing exceptions by keeping only the test rules.

  2. Add test rules

    Open the editor for this configuration and add the rules you need under [Rule]. Put DOMAIN exceptions before DOMAIN-SUFFIX, then leave a FINAL rule at the end that fits your goal. Save the changes.

  3. Check routing

    Go to Home → Global Routing → Config, then confirm the selected file under Config. Make sure the proxy policy on Home uses a server you already have access to and can connect to.

  4. Send a new request

    Reconnect before visiting the test target so the request doesn’t reuse a long-lived connection established before your changes. Check the target and applied policy in the app’s request log; a cached webpage can’t confirm that the new rules took effect.

  5. Check the fallback

    Visit a target that isn’t in your domain list and check whether it uses the policy specified by FINAL. If the result differs, check preceding rules, the destination IP, and the active configuration in that order. Don’t immediately add a broader keyword rule.

For the three example rules in section 3, the expected results are DIRECT for api.example.com, PROXY for www.example.com, and DIRECT for other unmatched targets. These are outcomes inferred from the rules, not the results of live tests on the example domains. Once you’ve substituted real domains, verify them in the request log. A latency test checks connection performance on its own; it can’t show which rule matched a webpage.

6. Tell rule issues apart from connection errors

First, identify which of two problems you’re seeing. If the request uses the wrong policy, check the routing mode, selected configuration, rule conditions, and rule order. If it uses the expected policy but the connection fails, check the destination service and the connection parameters for your existing server. Rules decide how requests are handled; they can’t fix an incorrect server port or an unreachable server.

Error: Connection refused

Cause and solution: The underlying connection may return this refusal error, often because the destination port isn’t listening or is explicitly rejecting the connection. First check which policy the request actually used. If it was PROXY, compare the server address and Port with your service provider’s details. For example, if the details specify 443, enter 443 instead of guessing based on commonly used ports.

Error: Operation timed out

Cause and solution: The underlying operation may return this timeout error when it doesn’t complete within the allotted time. This doesn’t necessarily indicate a rule syntax problem. Test your existing connection under Home, then check the request target and policy. Separately check your current network, whether the destination is reachable, and whether the server is available. The exact wording in the app’s logs may vary depending on the source of the error.

Why does a DOMAIN-SUFFIX rule still use DIRECT?

Under Home → Global Routing, select Config, then confirm that Config has the file you just saved enabled. Next, check the top of [Rule] for an earlier matching DIRECT or FINAL rule. The condition should contain only the domain—no protocol, path, or port.

How can I send one subdomain direct without affecting other subdomains?

Put DOMAIN,api.example.com,DIRECT before DOMAIN-SUFFIX,example.com,PROXY. After saving, send new requests and check the policy for both api.example.com and another subdomain. Don’t test just one of them.

Why do some images still fail to load when the webpage opens?

Check the actual domain of each failed request, not just the page address. Images may come from a separate domain, or the request may have matched PROXY but failed to connect. Review the request log before deciding whether to add DOMAIN or DOMAIN-SUFFIX. Avoid using an overly broad DOMAIN-KEYWORD rule that could catch unrelated targets.

Will updating a subscription also change rules I wrote myself?

First distinguish a subscription for connection details on Home from updates to a rule file under Config. Updating an existing connection subscription doesn’t edit the current [Rule]. If the active configuration file itself is remotely updated, check its contents again afterward and keep custom changes in a copy you control.

When troubleshooting, change one condition at a time and keep the rule lines and request results from before and after each change. Check in this order: active configuration, Global Routing, match order, domain or IP, and connection parameters. This helps separate routing decisions from network connection issues. For a full guide to configuration options, see the user guide. For where to check protocol parameters, see the protocol reference.

Download Shadowrocket