August 9, 2026 · Rules & Routing · About 9 minutes

How to Write Shadowrocket Rules: DOMAIN-SUFFIX, GEOIP, IP-CIDR, and FINAL Explained

Learn what DOMAIN, DOMAIN-SUFFIX, DOMAIN-KEYWORD, GEOIP, IP-CIDR, and FINAL match, how rule order works, and what PROXY, DIRECT, and REJECT mean.

At a glance

Start by choosing what to match, then select an outbound policy, and finally check the rule order. This guide is for users who have added their own server to Shadowrocket and are ready to edit Config. You’ll learn to distinguish domain rules from IP rules, write a minimal rule set with FINAL, and check connection logs to confirm which rule matched. Example domains and reserved IP addresses are for explaining syntax only; they are not usable connection services.

1. Prerequisites and rule order

Rules go in the [Rule] section of a configuration file. The standard rules covered here are checked from top to bottom. Once a rule matches, its policy applies, and Shadowrocket does not continue looking for a “more specific” rule below it. Put exceptions before broader rules, and place FINAL at the end.

Before testing, go to Home → Global Routing, select Config, and confirm that the file currently enabled in Config is the one you just edited. When Proxy or Direct is selected, the rule-by-rule results described here should not be used to explain every request. Scene involves scene selection, so it is not a suitable starting point for a minimal rule test.

Request destinationActive configurationRules checked in orderMatching policyConnection result

Rules determine how traffic is handled; they do not fill in server settings or guarantee that a destination is reachable. Even when a request matches PROXY, a connection can still fail if your server address, port, or authentication details are incorrect. During testing, record “which rule matched” separately from “whether the connection succeeded.”

6 types
Rules covered here: DOMAIN, DOMAIN-SUFFIX, DOMAIN-KEYWORD, GEOIP, IP-CIDR, and FINAL
3 policies
Policies used here: PROXY, DIRECT, and REJECT
1 final rule
The minimal example uses FINAL to handle requests that did not match an earlier rule

2. DOMAIN, DOMAIN-SUFFIX, and DOMAIN-KEYWORD

A domain rule follows the format rule type,match value,policy, with fields separated by standard commas. The match value is a hostname, not a full URL. Don’t include https://, a path, query parameters, or :443 in the domain field. These three rule types cannot distinguish between different page paths on the same host.

RuleWhat it matchesExample that does not match
DOMAIN,example.com,DIRECTThe exact hostname example.com onlywww.example.com
DOMAIN-SUFFIX,example.com,PROXYexample.com and its subdomains, such as img.example.comnotexample.com
DOMAIN-KEYWORD,example,REJECTA destination whose hostname contains the string examplesample.test

DOMAIN-SUFFIX matches by domain hierarchy and is usually the best way to match a domain and all its subdomains. Don’t write *.example.com; enter example.com directly. DOMAIN-KEYWORD matches more broadly and could also match myexample.test, so make sure it won’t catch unrelated destinations.

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

In this standalone example, account.example.com matches the first rule and uses DIRECT, while img.example.com matches the second and uses PROXY. If you swap the first two lines, the account subdomain will match the suffix rule first, leaving the exact-match rule below it with no chance to apply. This is a rule-order issue, not a matter of DOMAIN having lower priority than DOMAIN-SUFFIX.

Takeaway: put exceptions first, broader matches after

When different hosts in the same domain need different policies, put the specific host’s DOMAIN rule before DOMAIN-SUFFIX. Use DOMAIN-KEYWORD only when you specifically need substring matching.

3. IP-CIDR, GEOIP, and no-resolve

IP-CIDR matches the network containing a destination IPv4 address; it does not match website names. The number after the slash is the prefix length: /32 represents a single IPv4 address, while /24 represents a network of 256 addresses. This count includes network and other reserved addresses, so it is not the number of usable servers.

IP-CIDR,192.0.2.8/32,DIRECT,no-resolve
IP-CIDR,198.51.100.0/24,REJECT,no-resolve
GEOIP,CN,DIRECT
FINAL,PROXY

The 192.0.2.8 and 198.51.100.0/24 addresses above are reserved for documentation and are shown only to illustrate the format. no-resolve means the IP rule won’t trigger an additional domain lookup for matching. If a usable destination IP is already available during matching, the rule can still use it. This does not disable all DNS or automatically match both domains and IPs.

If you want a specific website to use a particular policy, an explicit domain rule is usually easier to verify. Use an IP rule when you need to manage a known address or network. Geographic database classifications may differ from where a service is actually hosted, so GEOIP does not prove a website’s identity.

4. PROXY, DIRECT, REJECT, and FINAL

The policy at the end of a rule tells Shadowrocket what to do after a match. PROXY sends traffic through a proxy; the actual server depends on your current selection and configuration. DIRECT connects to the destination directly, and REJECT blocks the request. These are not protocols and cannot replace a server’s Type, address, or port.

SyntaxMeaningWhat to verify
DOMAIN,example.com,PROXYUse a proxy for this hostAfter the rule matches, verify which server is actually used
DOMAIN,example.com,DIRECTConnect directly to this hostWhether the current network can reach the destination directly
DOMAIN,example.com,REJECTReject requests to this hostWhether rejecting the request is what you intended
FINAL,PROXYUse PROXY for requests that did not match an earlier ruleWhether the fallback policy is what you expect

FINAL has no “match value” field. Its format is FINAL,policy; don’t write FINAL,example.com,PROXY. If placed in the middle of the list, it handles all remaining requests before later rules can work as intended. Choose DIRECT or PROXY as the fallback based on your own needs; there is no one-size-fits-all answer.

5. Save and test a minimal configuration in Config

Keep a copy of your original configuration before editing a local test file. Don’t replace the entire contents of your configuration with the rule block below; it shows only the [Rule] section. If the original file already has this section, edit it in place to avoid confusion from creating multiple [Rule] sections.

  1. Keep a backup

    Open Config, confirm which file is enabled, and back up its contents before creating a separate local test configuration. Note your current Global Routing selection so you can restore it after testing.

  2. Edit the rules

    In Config, open the test file for editing and find [Rule]. Enter the minimal example below. Check the commas, number of fields, and position of FINAL, then save.

  3. Enable the configuration

    In Config, select the saved test file, then go to Home → Global Routing → Config. In Home, confirm that the selected server is one you already have and that its settings are correct.

  4. Make a new request

    Start a new connection to the destination, then check the app’s connection log for the destination, matched rule, and policy used. Existing long-lived connections aren’t suitable for testing recently changed rules. If needed, close and reopen the destination app.

  5. Add rules one at a time

    Once the minimal configuration behaves as expected, add one rule at a time and test again. If the result changes, first remove the rule you just added rather than changing DNS, server settings, and multiple rule groups at once.

[Rule]
DOMAIN,account.example.com,DIRECT
DOMAIN-SUFFIX,example.com,PROXY
IP-CIDR,192.0.2.8/32,DIRECT,no-resolve
GEOIP,CN,DIRECT
FINAL,PROXY

The expected order in this example is: the account subdomain uses DIRECT; other example.com subdomains use PROXY; address rules and GEOIP are checked next; and FINAL handles anything left over. The example domains illustrate rule matching. For real connection tests, use a destination you’re authorized to access and whose hostname you know.

6. Troubleshooting rules and timeouts

A page that won’t load is not enough to prove there’s a rule syntax error. First check the active file and Global Routing, then inspect the actual destination and matching rule, and finally check the outbound connection. Don’t immediately change every rule to PROXY when a connection fails; that makes it harder to tell a matching problem from a connection problem.

Error: timeout

Cause: A connection test or request did not finish within the time limit. This result alone can’t tell you whether the cause was the rule, the destination network, or the server in use.

What to do: First check which policy the request actually matched. If it matched PROXY, use Home → Connectivity Test to test the current server, then verify your server address, port, and authentication details.

SymptomCheck firstWhat to change
All requests use the same outbound routeWhether Home → Global Routing is set to ConfigSwitch back to Config, then check which file is enabled
The exact-domain rule doesn’t matchWhether a suffix or keyword rule appears earlierMove the exact-match rule that should take priority higher in the list
Rules later in the list never take effectWhether FINAL is in the middle of the listMove FINAL after the standard rules
The main page loads, but images or APIs failWhether the failed request uses a different hostnameAdd rules for the actual destinations; don’t rely only on the address bar
An IP rule doesn’t match as expectedThe actual destination address, network, and no-resolveCheck which address information is available for matching; a domain’s location does not determine its IP’s location

Finally, check the text itself: use standard commas, keep keywords such as DOMAIN-SUFFIX unchanged, and don’t paste explanatory text into a rule line. Three-field rules such as DOMAIN have a different number of fields from FINAL. If you add a named policy, make sure that name exists in the active configuration. If restoring the original configuration fixes the issue, that helps narrow down the change, but you should still identify the cause by reverting changes one at a time.

Verify on the App StoreCheck the developer and app ID