This guide is for people already using Shadowrocket on an iPhone or iPad who have their own server details or subscription but aren't sure why a rule matches—or doesn't. Check Global Routing and the active configuration first, then distinguish domain matches from IP matches and the FINAL fallback. By the end, you'll be able to write a minimal rule snippet and check where requests actually go using request records. Example domains and reserved addresses are for illustration only; no connectivity service is provided.
1. Before rules can work: Global Routing and the active configuration
Shadowrocket rules are not a server list. The server selected in Home determines the proxy exit used for connections, while the configuration in Config contains rules and other settings. Importing or updating your own subscription does not automatically switch to the configuration with the rules you expect. Check these separately before troubleshooting.
Check Global Routing in Home. This guide covers requests evaluated rule by rule when Config is selected. Proxy and Direct are global routing modes; their results alone don't prove that a specific rule in the configuration matched. Scene follows its selected scene settings and is not another name for Config.
| Setting | What it means | How to test in this guide |
|---|---|---|
Config | Apply the rules in the active configuration. | Select this mode, then check that the active configuration is correct. |
Proxy | Use global proxy routing. | Useful for isolating an exit issue, but not for validating individual rules. |
Direct | Use global direct routing. | Compare with a direct connection, then switch back to Config when the test is done. |
Scene | Follow the settings for the selected scene. | Check the scene settings first; use Config for an initial rule test. |
2. Rule syntax and order: first match wins
A typical rule consists of an English keyword, a match value, and a policy, separated by commas. FINAL has no match value, so it uses two main fields: the keyword and the policy. DIRECT means connect directly; PROXY below means send traffic through the proxy. Make sure the selected proxy is working before using it. Any custom policy group name must also exist in the configuration.
[Rule]
DOMAIN,login.example.com,DIRECT
DOMAIN-SUFFIX,example.com,PROXY
DOMAIN-KEYWORD,example,PROXY
IP-CIDR,192.0.2.0/24,DIRECT,no-resolve
GEOIP,CN,DIRECT
FINAL,PROXY
This snippet illustrates syntax; it is not a complete, ready-to-connect configuration. Shadowrocket checks rules from top to bottom and applies the policy for the first matching rule. It does not continue looking for a “more specific” match. A precise rule does not automatically take priority over a broader one.
In the example above, a request for login.example.com matches the first line and uses DIRECT. If DOMAIN-SUFFIX comes before DOMAIN, login.example.com matches the suffix rule first and goes to PROXY; the exact rule below never gets a chance to handle that request.
- Put a small number of high-priority exceptions first, such as a specific login domain.
- Place general rules covering a domain and its subdomains after exceptions.
- Check that broad keyword and geographic address matches don't shadow later rules.
- Put FINAL after every rule that needs to be checked. Don't add active exceptions below it.
3. Where DOMAIN, DOMAIN-SUFFIX, and DOMAIN-KEYWORD differ
All three keywords match domains, but their coverage differs. Enter a hostname or keyword—not a full URL. Don't include https://, a page path, query parameters, or a port. For example, connecting to login.example.com on port 443 doesn't mean the DOMAIN match value should be login.example.com:443.
| Rule example | Matches | Does not match |
|---|---|---|
DOMAIN,example.com,DIRECT | example.com | www.example.com、example.com.test |
DOMAIN-SUFFIX,example.com,PROXY | example.com、www.example.com、a.b.example.com | notexample.com、example.com.test |
DOMAIN-KEYWORD,example,PROXY | example.com、myexample.test、example.net | Domains that don't contain example |
DOMAIN: match one exact hostname
DOMAIN is easiest to review when api.example.com and www.example.com need separate handling. It does not implicitly cover subdomains: DOMAIN,example.com,DIRECT won't also match api.example.com. When writing rules for an app, remember it may contact several hostnames for login, APIs, images, and other resources. The homepage domain alone won't tell you where every request goes.
DOMAIN-SUFFIX: cover a domain and its subdomains
DOMAIN-SUFFIX,example.com,PROXY matches the root domain and all levels of subdomains; no wildcard is needed. It isn't a search for any string ending in the same characters: notexample.com lacks the domain-level boundary, so it isn't a subdomain of example.com.
DOMAIN-KEYWORD: match domains containing a string
DOMAIN-KEYWORD doesn't require the keyword to fall on a domain-level boundary. It's useful when you really need to match multiple domains containing a string, but it can also produce unexpected matches. For example, example matches myexample.test. If you only want to handle the example.com domain and its subdomains, prefer DOMAIN-SUFFIX over a broader keyword.
4. GEOIP and IP-CIDR: match the destination address
GEOIP checks the destination IP's geographic classification in an address database. GEOIP,CN,DIRECT means use DIRECT when the database classifies the destination IP as CN. It doesn't check the website's language, where its domain was registered, or the user's location—and it can't guarantee that every service from a brand always uses addresses in the same region.
IP-CIDR matches a specific IPv4 range. IP-CIDR,192.0.2.0/24,DIRECT covers 192.0.2.0 through 192.0.2.255; /24 means the first 24 bits are the network prefix, not a port number. 192.0.2.0/24 is a range reserved for documentation and is shown here only to explain matching; it is not a usable server address.
IP-CIDR,192.0.2.0/24,DIRECT,no-resolve
GEOIP,CN,DIRECT
FINAL,PROXY
Whether an IP rule needs to resolve a domain first can affect troubleshooting. The optional no-resolve parameter tells this rule not to initiate a DNS lookup just to match an IP. If the destination IP is already known, it can still be checked against the address. This does not “turn off DNS” or mean a webpage will never need name resolution. If the destination IP isn't available, the rule may be skipped and later rules can be checked.
- Prioritize domain exceptions: For services that should be handled by domain, put the relevant DOMAIN or DOMAIN-SUFFIX rule before a broad GEOIP rule.
- Database categories aren't service categories: CDN addresses, DNS results, and how the address database classifies an IP can all affect GEOIP results. Check the actual destination IP.
- Check address families separately: An IPv4 range in IP-CIDR doesn't cover IPv6. For IPv6 addresses, use the corresponding IP-CIDR6 rule separately.
- Ports aren't CIDR ranges: Destination port 443 and the /24 network prefix are different things. Don't append a port to the IP-CIDR address field.
5. Why FINAL belongs on the last line
FINAL is the fallback rule: if none of the preceding rules match, it applies the specified policy. It has no domain or network-range restriction, so placing it in the middle catches every request that reaches it and prevents rules below from being checked. “Last” means the end of the entire active rule sequence—not just the last section visible in the editor.
[Rule]
DOMAIN,login.example.com,DIRECT
DOMAIN-SUFFIX,example.com,PROXY
GEOIP,CN,DIRECT
FINAL,PROXY
FINAL,PROXY and FINAL,DIRECT are both explicit fallback choices; neither is right for everyone. The former sends unmatched requests through the proxy, while the latter connects directly. FINAL,PROXY requires a working proxy exit. With FINAL,DIRECT, unknown destinations connect directly. Before changing this setting, consider what you need—not just whether one webpage opens.
“Why doesn't my more specific rule match?”
Check whether a DOMAIN-SUFFIX, DOMAIN-KEYWORD, or FINAL rule above it has already matched. Move the DOMAIN exception ahead of broader rules, then make a new connection and check again.
“Can I add a rule after FINAL?”
You can add text, but that rule won't handle requests already caught by FINAL. Move new rules above FINAL and keep one clear fallback at the end.
“Will changing FINAL to DIRECT fix it?”
Not necessarily. It may simply bypass an unavailable proxy exit. Go back to Home and check the selected server, then see whether a more specific rule should handle the domain.
“Do subscription updates also update the rules?”
Updating a server subscription and updating a rule configuration are separate operations. Check the active configuration in Config, then confirm whether you updated the server list or the configuration file. A successful list refresh doesn't prove the rules were updated.
6. Minimal verification: change one rule at a time
Track both the expected policy and the actual request. A webpage loading only shows that one request succeeded; it doesn't prove whether it used DIRECT or PROXY. These steps don't require changing your subscription or protocol settings. Exit protocols such as Shadowsocks, VMess, and VLESS are separate from rule keywords.
-
Keep the original configuration
Check the active configuration in Config and save a recoverable copy or the original text before making changes. Note the current FINAL policy. Don't overwrite your only working configuration.
-
Check the routing mode
In Home → Global Routing, select Config. Then return to Config and confirm that the configuration you intend to test is active—not another configuration with the same name or a remote one.
-
Add an exact-match exception
In the rules section of the active configuration, add a DOMAIN rule for a real destination you can verify. Place it ahead of broad rules and FINAL. example.com in this guide is for syntax illustration only, not a proxy connectivity test target.
-
Make a new request
Save the configuration and make sure it is active. Close existing connections in the target app, then make a new request. Keep the server selected in Home unchanged so connection reuse or a different exit doesn't affect the result.
-
Check the request record
Use the fields shown in the interface to check the hostname, destination IP, matched rule, and actual policy in the request record or log. If the record doesn't include enough detail, enable the relevant logging first and repeat the same request. Don't infer the exit from latency alone.
7. When a rule matches but the request still fails: troubleshoot by layer
Rules choose where traffic goes; they can't guarantee that the destination, DNS, or proxy server is always available. If the request record shows the expected rule matched, check the connection stages that follow. The messages below are errors you may encounter during network troubleshooting, not rule syntax errors. Their exact wording depends on which layer reports the problem, so a single line isn't enough to identify a rule issue.
Error: Connection refused
Cause: A connection endpoint refused the connection. The destination port or proxy server port may not have a service listening on it.
What to do: Check the record for the address and port the client tried to reach. Then confirm that the server port in Home matches the service details you already have. If the failure is at the destination, check that service rather than broadening domain rules.
Error: Operation timed out
Cause: An operation didn't complete within the time limit. The issue could involve the network path, proxy connection, or destination response; a timeout alone doesn't show which one.
What to do: Use connection records around the error to identify the stage. Temporarily switch Home → Global Routing to Proxy or Direct for comparison, then restore Config. Keep the test destination the same.
Error: No route to host
Cause: The network path used for the connection can't reach the destination address. This doesn't mean the DOMAIN or FINAL fields are incorrect.
What to do: Check that the current network is available and that the actual destination IP and address family are as expected. Then confirm whether the request ultimately used DIRECT or the proxy exit, and troubleshoot that path.
If the failure is during DNS resolution, first check whether the DNS request succeeded. If server authentication failed, check your own server settings. Don't hide these issues by switching all requests to DIRECT, and don't rewrite the entire ruleset to fix one error. Keep the test conditions consistent so you can tell whether the fix worked.
- Configuration: Home → Global Routing is set to Config, and the correct file is active in Config.
- Syntax: Use standard commas, omit URL paths from domain fields, and confirm the policy name is valid.
- Order: Put exact exceptions before broad matches, and place FINAL at the end of the active rule sequence.
- Result: The new request's hostname, destination IP, and actual policy match expectations—not just the fact that the webpage loads.