1. What Rule Providers Solve—and What They Do Not

A rule provider lets a Clash-compatible core load a reusable list of matching conditions separately from the main configuration. Instead of copying dozens or hundreds of entries into rules:, you define a provider once, point it at a rule file, and reference it with a RULE-SET rule. This separates the list of destinations from the routing policy that decides what to do when one of them matches.

For example, a maintained domain list can contain entries for advertising hosts, while the main configuration says that a match should use REJECT. The provider supplies the match conditions; the RULE-SET line supplies the policy. You can reuse the same list with a different policy in another configuration without changing the source file.

Rule providers are not supported identically by every core or historical release. The examples in this guide use the mihomo-style configuration supported by compatible versions. A GUI client may offer a provider editor or generate configuration fields for you, but the active core still has to understand the provider type, behavior, and format. Check the core name and version before treating an “unknown field” error as a YAML formatting problem.

Provider field Purpose Typical choice
type How the provider obtains its rule file http for a remote hosted file; file for a local file, where supported
behavior How the provider interprets each payload entry domain, ipcidr, or classical
format The serialization format of the provider file yaml for a file containing a payload list
url and path Remote source and local cache location for an HTTP provider A direct raw-file URL and a writable path inside the core's working area
interval How often the core checks for an updated remote file A deliberate interval in seconds, such as 86400 for 24 hours

2. Choose the Provider Behavior and Build a Small YAML File

Pick the behavior that matches the data you need to maintain. A domain provider is suited to domain-oriented entries, an ipcidr provider to IP ranges, and a classical provider to supported rule expressions such as exact-domain, suffix, keyword, or IP-CIDR rules. The format is not a substitute for behavior: format: yaml tells the core how the file is serialized, while behavior tells it how to interpret the entries.

A domain provider

For a domain list, use a YAML document with a top-level payload sequence. Keep entries consistent with the chosen provider behavior and the syntax accepted by the core version you run. A small example is easier to inspect and test than a large list copied from multiple sources.

payload:
  - "+.ads.example"
  - "+.metrics.example"
  - "+.tracking.example"

A classical provider

Choose classical when the list needs more than domain entries, or when it needs explicit rule types. Each payload item is a rule expression, not a complete main-configuration rule with a final outbound policy. For example, a list might include a domain suffix and a private-network IP range:

payload:
  - DOMAIN-SUFFIX,example.net
  - IP-CIDR,192.168.0.0/16,no-resolve

Be precise about CIDR notation, commas, and option placement. In particular, no-resolve is an option used with relevant IP rules; it is not a replacement for a valid address range. If a rule type or option is not supported by the active core, the provider can fail even though the surrounding YAML parses correctly.

Reference the file from the main configuration

Declare the provider under the top-level rule-providers: key, then reference its name under rules:. The following shows a remote YAML domain list. Replace the example URL with a direct URL to your own published file, and make sure the named policy exists in your configuration.

rule-providers:
  maintained-domains:
    type: http
    behavior: domain
    format: yaml
    url: "https://raw.githubusercontent.com/OWNER/REPOSITORY/main/rules/domains.yaml"
    path: ./rule_providers/maintained-domains.yaml
    interval: 86400

rules:
  - RULE-SET,maintained-domains,REJECT
  - MATCH,Proxy

The path is a local cache file used by the core; it is not the URL and is not a directory name. Confirm that the process can create or update the parent directory. Also verify that REJECT and Proxy are valid policies for your setup. A provider can load successfully while a misspelled group name still prevents the intended routing behavior.

3. Host a Rule File on GitHub Without Making Updates Fragile

A repository is a convenient place to review changes, keep a history, and publish a static rule file. For an HTTP provider, the core needs a direct response containing the file itself. A repository page, a file-view page, a sign-in page, or an HTML error page is not the same as a raw YAML response. Use the direct raw-file address for the chosen branch and path, then test that exact address from the machine running the core.

  1. Create a focused repository layout. Keep provider data in a predictable location, for example rules/domains.yaml and rules/private-ranges.yaml. Give files names that describe their contents rather than the action applied to them. The same list may later be used with a different policy.
  2. Publish only the data intended to be public. A public raw-file URL can be fetched by anyone who has it. Never commit subscription URLs, access tokens, private hostnames, personal IP addresses, or other credentials into a rule list. Do not assume an obscure filename makes a public file private.
  3. Use a stable branch and path. A URL to a moving branch is easy to update, but its contents can change without a configuration edit. Review changes before merging, and avoid renaming or moving a file without updating every configuration that references it.
  4. Choose an update cadence that matches the data. A daily list may reasonably use interval: 86400; a list that rarely changes can use a longer interval. Very short intervals create needless requests and can add load without improving the quality of routing decisions.
  5. Keep a local copy and a recovery plan. The provider's path acts as a local cache, but it should not be the only copy of a carefully maintained list. Keep the source in version control and retain the last known-good revision so that a bad update can be reverted quickly.

Public hosting is not a delivery guarantee. Network outages, repository changes, rate limits, removed files, and transient HTTP errors can interrupt updates. A core may continue to have a cached provider file, but do not assume every version handles a missing or invalid refresh in the same way. Test the behavior of the actual core you deploy, and inspect its logs after a provider update.

For stronger change control, review each pull request or commit before publishing it. If you need a configuration to use an immutable revision rather than the latest branch contents, use a raw-file URL that identifies a specific commit, provided that the hosting service and your core can fetch it. Pinning improves reproducibility but also means updates require an intentional URL change. Avoid using a moving branch when the priority is repeatable deployments, and avoid pinning indefinitely when you need timely security or blocking-list updates.

4. Validate YAML, HTTP Responses, and Core Compatibility Separately

“The YAML is valid” is only one part of provider testing. A file can be valid YAML but have the wrong top-level key, the wrong entry syntax for its behavior, a broken URL, or a policy name that does not exist. Check each layer independently so that an error message has a useful scope.

Check the remote response first

Request the exact raw-file URL from the host where Clash or mihomo runs. Confirm that the request completes, the status is successful, and the response body begins with the expected YAML content rather than HTML. If your tooling is available, inspect the response headers and body with a command such as:

curl -L --fail --show-error "https://raw.githubusercontent.com/OWNER/REPOSITORY/main/rules/domains.yaml"

This is a diagnostic example, not a substitute for testing the core's own network access. A browser may reach a file while the service process cannot, because it uses a different proxy, DNS path, certificate store, firewall rule, or network namespace. If a provider fails only in the client, compare the core's logs with a request made from the same device and network.

Check structure and indentation

YAML indentation is structural. Use spaces rather than tabs, keep the entries under payload:, and quote values when punctuation could be interpreted unexpectedly. A syntax checker can catch malformed YAML, but it cannot decide whether +.example is a meaningful domain entry or whether a CIDR range is the one you intended. Review the data itself as well as the parser result.

payload:
  - "+.example.org"
  - "+.static.example.org"

For a main configuration, use the validation command supported by the installed core. A common mihomo command-line check is mihomo -t -f config.yaml; confirm the options available in your installed version before relying on it. A configuration test can identify unsupported fields and structural errors, but it may not prove that a remote provider can be fetched during normal operation. Follow it with a real provider update and inspect the core's logs.

Test a small sample before publishing a large list

Start with two or three entries whose expected behavior you can verify. Load the provider, confirm that the core reports it as available, and inspect the rule or connection view exposed by your client. Generate fresh connections for tests; existing connections may keep their current route. Check one entry that should match, one similar hostname that should not match, and one ordinary destination that should reach the fallback rule.

When a rule does not behave as expected, check the data, provider status, reference name, policy name, mode, and rule order in that sequence. Do not diagnose a provider by looking only at a website loading successfully: a direct route, cached response, or existing connection can make a broken rule appear to work.

5. Control Rule Priority and Make Updates Reviewable

Provider rules participate in the main rule sequence at the position of their RULE-SET reference. The core does not automatically move a provider above more specific rules or choose the most specific match across the whole configuration. In ordinary rule mode, matching proceeds in order and the first applicable rule determines the route. A correct provider placed too late may never be reached.

rules:
  - DOMAIN,login.example.org,DIRECT
  - RULE-SET,maintained-domains,REJECT
  - GEOIP,CN,DIRECT
  - MATCH,Proxy

Here, the exact-domain exception appears before the broader provider rule. If the provider also matches login.example.org, the exception can still take effect because it is checked first. If the provider reference is placed above that exception, the broader action may win instead. Keep MATCH at the end as the fallback, and ensure the fallback policy exists.

Symptom Likely cause Useful check
Provider cannot be downloaded Wrong URL, inaccessible file, network restriction, or non-raw HTML response Fetch the exact URL from the core's host and inspect the response body
YAML parses but provider is rejected Wrong behavior, unsupported field, or invalid payload entries Compare the payload structure with the active core's supported provider format
Provider loads but traffic uses another route Rule order, wrong policy name, wrong active configuration, or traffic not entering the core Inspect the active mode, rule order, connection details, and selected policy
Changes do not appear immediately Refresh interval has not elapsed, update failed, or an existing connection is being observed Trigger a supported provider update, check logs, then create a fresh connection

For a maintainable workflow, make one focused change at a time: edit the provider file, review the diff, validate its YAML and entries, publish it, fetch the raw response, refresh the provider, and test representative destinations. Record the provider name, behavior, source path, interval, and intended policy in your change notes. If several lists are combined, keep their purposes distinct—for example, separate domain and IP data rather than forcing unrelated entries into one provider.

When an update causes unexpected routing, revert the provider data or restore the previous known-good revision first. Then investigate the change in isolation. This is safer than simultaneously changing the rule list, the main configuration, the core version, and the selected proxy group. A provider workflow is reliable when its source is reviewable, its format matches the declared behavior, its refresh is observable, and its reference sits at the intended position in the rule sequence.