Shadowrocket Custom Rules: Rule Order, FINAL Fallback, and PROXY/DIRECT/REJECT

Learn how Shadowrocket evaluates rules from top to bottom, why specific exceptions come first and FINAL belongs last, and when to use PROXY, DIRECT, or REJECT.

At a glance

Shadowrocket custom rules are checked in order, and the first matching rule determines the policy. Put specific exceptions before broader rules, and place FINAL at the end of the [Rule] section. This guide applies to iPhone, iPad, Mac, Windows, Android, and Linux users learning to read rule files; interface details may vary by device. By the end, you’ll be able to build a minimal rule set, distinguish PROXY / DIRECT / REJECT, and troubleshoot by checking the active config, routing mode, match order, and outbound connection.

1. Check Config and routing mode before testing rules

Turning on the connection does not necessarily mean your custom rules are being used. On iPhone or iPad, first open Config and confirm that the config you intend to edit is selected, then return to Home and check Global Routing. To test the rules in this guide, use Config. Don’t test with Proxy or Direct first and conclude from that alone that your rules are wrong.

This guide assumes you already have a working service configuration. Rules determine how requests are handled; they cannot provide connection credentials or fix an unreachable server. We do not provide, sell, or recommend nodes or subscriptions. Before editing, save a copy of your current config so you can compare or restore it if needed.

Global RoutingWhat each mode meansWhat it helps you test
ConfigApply policies from the active config’s rulesRule order, exceptions, and FINAL
ProxyPrimarily routes traffic through the proxy; it is not the mode for testing each rule in this guideWhether the selected proxy connection works
DirectPrimarily connects directlyDirect reachability on the current network
SceneFollows the configured scene logicScene selection and switching; not used as the baseline for this guide
New connection request Active config Rules checked in order Matching policy Outbound connection

Settings → On Demand controls when connections start; it does not change the order of rules in [Rule]. If the connection state changes after switching networks, check On Demand first, then inspect the rules. A tunnel that is not connected and a rule that matches incorrectly are separate issues.

2. Rule syntax: type, match value, and policy

Most rules use a comma-separated format: rule type, match value, policy. Keywords and separators use English characters. FINAL has no match value, so write FINAL,PROXY. The example below is a teaching sample for the [Rule] section, not a complete config with servers, DNS, and other settings. Add it to an existing working config for testing; it cannot connect on its own.

[Rule]
DOMAIN,blocked.example.com,REJECT
DOMAIN,local.example.com,DIRECT
DOMAIN-SUFFIX,example.com,PROXY
IP-CIDR,192.0.2.0/24,DIRECT,no-resolve
GEOIP,CN,DIRECT
FINAL,PROXY
5 types
This example uses DOMAIN, DOMAIN-SUFFIX, IP-CIDR, GEOIP, and FINAL
3 policies
This example uses PROXY, DIRECT, and REJECT
1 rule
FINAL goes at the end of [Rule] as the fallback

example.com and its subdomains illustrate matching behavior. 192.0.2.0/24 is a documentation-only example network, not a usable service address. These rules demonstrate syntax and order; they do not show that any service is available at those addresses. Test with destinations you’re authorized to access, and choose DIRECT or REJECT based on the actual use case.

3. Rules are checked top to bottom: put specific exceptions first

Shadowrocket does not collect all matching rules and then automatically choose the “most specific” one. For a given request, earlier rules are evaluated first. Once a rule matches and determines the policy, later regular rules do not override it. So even an exact domain match will not get priority over a broader suffix rule if it appears below it.

Exception first: expected result

First line
DOMAIN,local.example.com,DIRECT
Second line
DOMAIN-SUFFIX,example.com,PROXY
Last line
FINAL,PROXY

local.example.com matches DIRECT first; other requests matching the suffix use PROXY.

Broader rule first: exception is shadowed

First line
DOMAIN-SUFFIX,example.com,PROXY
Second line
DOMAIN,local.example.com,DIRECT
Last line
FINAL,PROXY

local.example.com already matches the first line, so the later DIRECT rule cannot change the decision.

In short: exceptions first, broader rules next, fallback last

When a new rule seems to have no effect, look above it for an existing rule that covers the same destination. Move any necessary exact-match exception ahead of that rule, then test with a new connection. This is more useful for finding the cause than repeatedly switching policies.

  1. Define the intent: for example, connect local.example.com directly and use the proxy for other example.com subdomains.
  2. Put the exact DOMAIN exception first, followed by the DOMAIN-SUFFIX rule. If you need a REJECT exception, place it according to the intended priority as well.
  3. Check whether an earlier rule already covers the destination, including rules brought in by the existing config.
  4. Save and confirm that this config is still selected. Test with a new connection rather than relying on an existing connection from an already-open page.

4. Why FINAL belongs last and how to choose a fallback

FINAL has no additional match conditions. If you put FINAL,PROXY at the start of [Rule], no rules have filtered requests yet, so later domain or IP rules never get a chance to handle them. Placing FINAL in the middle likewise shadows every rule below it. Keep one clear FINAL rule at the end of the [Rule] section, not just anywhere in the config file.

[Rule]
DOMAIN,local.example.com,DIRECT
DOMAIN-SUFFIX,example.com,PROXY
GEOIP,CN,DIRECT
FINAL,PROXY

This example means: handle explicit domain requirements first, use GEOIP for the remaining destination IPs, then send anything still unmatched to PROXY. FINAL is not a backup route for failed connections, nor does it automatically send traffic DIRECT when a proxy fails. If a rule selects PROXY and the connection fails, the presence of FINAL,DIRECT at the end will not trigger an automatic direct retry.

Fallback ruleHow unmatched requests are handledCheck before changing
FINAL,PROXYSend to the proxy policyThe proxy outbound works and is the expected route for unknown destinations
FINAL,DIRECTConnect directly to the destinationUnlisted destinations should connect directly over the current network
FINAL,REJECTReject all other requestsEvery destination that should be allowed is listed; otherwise, normal traffic may be blocked

Don’t keep changing the fallback just to make a page load temporarily. First decide how unlisted destinations should be routed, then add any necessary exceptions. Treating FINAL as a clearly defined default policy makes it easier to explain routing decisions as your rules grow.

5. PROXY, DIRECT, and REJECT are not connection protocols

These keywords describe policies, not protocol names. Shadowsocks, VMess, VLESS, Trojan, Hysteria2, and WireGuard are protocol concepts used in connection configs; writing PROXY does not automatically switch the active connection to any particular protocol. If your config uses a custom policy group, check its name and the selected outbound. An undefined group name is not a usable policy.

PolicyWhat it doesCommon misconception
PROXYSends matching requests through the proxy outbound; check the currently selected connection or relevant policy settingsDoes not automatically choose the fastest route or guarantee that the server is reachable
DIRECTConnects directly to the destination over the current networkDoes not turn off the entire VPN or mean that all other requests connect directly
REJECTRejects matching requestsDoes not fix the connection or lower priority while waiting to retry

For example, DOMAIN,blocked.example.com,REJECT rejects that exact domain; it does not also reject every example.com subdomain. To reject the entire domain and its subdomains, use DOMAIN-SUFFIX,example.com,REJECT. That broadens the impact, so check that you won’t block login, API, or resource domains by mistake.

6. IP-CIDR, GEOIP, and DNS: a domain request is not an IP request

Domain rules can generally match the domain in a request, while IP-CIDR and GEOIP need destination IP information. A domain may resolve to multiple addresses, and addresses can change with the network, DNS response, or service deployment. Hard-coding one IP you saw once as a DIRECT rule may not cover the next visit, and does not mean the entire domain will always use the same policy.

no-resolve prevents a rule from actively triggering domain resolution solely to evaluate that IP rule. It does not “disable DNS,” nor does it mean every domain request can be evaluated by that IP rule. Without a destination IP available for the match, it cannot force a network-range match.

HTTPS commonly uses destination port 443, but the DOMAIN-SUFFIX rule in this guide has no port condition. It matches the domain, not just traffic on port 443. If an API still fails, check the destination domain, actual IP address, destination port, and connection error separately. Don’t assume an application server rejection means the rule failed to match.

7. How to verify changes: change one variable at a time

Test rule matching separately from whether the selected outbound can complete the connection. The first tells you which policy handled a request; the second tells you whether the connection succeeded. If a request matches PROXY but the proxy connection fails, the rule order may still be correct. Conversely, a page loading does not prove that traffic used the intended policy.

  1. Keep a baseline: Copy the current working config and note its Global Routing mode, selected connection, and the domain you’ll test.
  2. Change one thing: Add one exact DOMAIN rule or change the order of two lines. Don’t change DNS, the connection protocol, and FINAL at the same time.
  3. Confirm the selected config: Open Config and check which config is active, then go to Home and confirm Global Routing is set to Config and the connection is active.
  4. Start a new connection: Close the old page and make the request again; if needed, end existing connections in the app. An established connection may continue using the route it started with.
  5. Check the records: Use the connection records or logs available on your device to inspect the destination, matching rule, and policy. If some fields aren’t shown, compare results with a temporary exact-match rule instead of guessing.
  6. Restore and document: If a change causes problems, restore the saved copy first. Once verified, merge the change into your everyday config and note what the rule is for.

I added DIRECT. Why is this domain still using PROXY?

First check that Global Routing is set to Config, then confirm you edited the active config. Look above the DOMAIN rule for a DOMAIN-SUFFIX rule or another rule that covers it. Move the necessary exception ahead of the broader rule, save, and test with a new connection.

I set FINAL to DIRECT. Why doesn’t it connect directly after the proxy fails?

FINAL handles only requests that didn’t match earlier rules; it does not handle connection errors after a request matches PROXY. Check which rule matched the request, then troubleshoot the current proxy outbound. If the intended behavior is direct access, add a correctly scoped DIRECT rule instead of relying on fallback after a failure.

Can a subscription update overwrite my custom rules?

First distinguish connection subscription updates on Home from remote config updates in Config. The former mainly refreshes connection details; the latter may reload rule content. Save a local copy before editing. If you need to keep a remote config up to date, check what the update replaces and avoid making a one-off change only to the remote content.

Why aren’t my rules working with On Demand enabled?

Check the automatic connection conditions in Settings → On Demand, then return to Home and check the actual connection state and Global Routing. On Demand controls when to connect; it does not automatically set the routing mode to Config or change rule order.

Use the same order for routine maintenance: specific exceptions first, broader rules next, and FINAL last. When something goes wrong, check the active config and match records before investigating outbound reachability. Don’t pile on duplicate rules to hide a connection issue you haven’t identified.

Download Shadowrocket