· Subscriptions & Config · 10 min read

Build Clash Rule Providers on GitHub: YAML Rules and Auto Updates

Move custom routing rules out of your main Clash Build Clash Rule Providers on GitHub: YAML Rules and Auto Updates. Learn how to write YAML rule sets, host them on GitHub, and Build Clash Rule Providers on GitHub: YAML Rules and Auto Updatesure behavior, format, path, and in…

What a Rule Provider Does—and What It Does Not Do

A rule provider lets a Clash-compatible core load a set of routing rules from a separate file instead of embedding every rule in the main configuration. The main config defines where to fetch or find the file, how to interpret its contents, and what action to take when a rule matches. This separation makes large lists easier to review, reuse, update, and roll back.

A rule provider is not a proxy subscription and does not create proxy nodes. It supplies matching criteria—such as domains or IP ranges—which the main config references with a RULE-SET rule. The policy after that reference still determines the action: a proxy group, DIRECT, REJECT, or another policy defined in the config. A provider can therefore be downloaded and parsed successfully while traffic still takes an unexpected route because the referencing rule is missing, appears too late, or points to the wrong policy.

GitHub is one possible place to host the provider file. A public repository can serve a raw YAML file over HTTPS, while Git keeps the source history and makes changes reviewable. Hosting does not guarantee that every network can reach GitHub, that a file is safe, or that an update has taken effect. The core must be able to fetch the URL, parse the file, and evaluate the provider at the point where it appears in the rule list.

Prepare a GitHub-Hosted YAML File

Start with a small, public repository or a dedicated directory in a repository you already maintain. Keep rule files in a predictable location, use clear filenames, and make changes through commits so you can inspect the diff or revert an accidental edit. For a public raw file, the URL generally follows this pattern:

https://raw.githubusercontent.com/OWNER/REPOSITORY/BRANCH/PATH/FILE.yaml

Replace each capitalized segment with the actual owner, repository, branch, and case-sensitive path. For example, a file at rules/social.yaml on the main branch would use a URL ending in /main/rules/social.yaml. Use the raw file URL, not the repository’s HTML page, a commit history page, or a link that opens GitHub’s file viewer. Those pages return web markup rather than the provider YAML the core expects.

Choose the provider behavior to match the structure of the file. A domain provider contains domain patterns, an ipcidr provider contains IP ranges, and a classical provider contains complete Clash rule expressions. Do not mix these formats just because they are all written in YAML. The following example is a domain provider file:

payload:
  - '+.example.net'
  - '+.media.example'
  - 'service.example.org'

The top-level key is payload. For a domain provider, entries are domain patterns rather than full lines such as DOMAIN-SUFFIX,example.net,Proxy; the action belongs in the main config. For a classical provider, by contrast, the payload contains complete rule expressions, for example:

payload:
  - DOMAIN-SUFFIX,example.net
  - DOMAIN,login.example.org
  - DOMAIN-KEYWORD,media

Check the target core’s documentation for the supported syntax and rule types before publishing a list. A rule that looks plausible may still be rejected if it uses an unsupported rule type, malformed punctuation, invalid indentation, or a value that does not match the selected behavior. Keep each entry on its own line, quote values where YAML punctuation could be ambiguous, and avoid adding unrelated config sections such as rules: or proxies: to a provider-only file.

Choose a Maintainable Repository Layout

Put files with similar purposes together, but avoid an overly complicated directory tree. Names such as ads.yaml, work-domains.yaml, or private-network.yaml make it easier to see what a provider is intended to match. Add a short README in the repository explaining each list’s scope, source, license, and review process. Do not put subscription tokens, private hostnames, or credentials in a public repository or in a public raw URL.

A branch URL such as main follows new commits, which is convenient when you want updates to arrive without changing the main config. It also means the content can change independently of that config. A commit-pinned URL gives a reproducible snapshot, but it will not follow later commits until you update the URL. Choose deliberately: automatic updates and a fixed, auditable snapshot are different maintenance goals.

Configure and Reference the Provider

Add a provider entry under rule-providers in the main config. Set a unique provider name, a download type, a local cache path, the matching behavior, the remote URL, and an update interval in seconds. The following example assumes the main config already defines a proxy group named Proxy:

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

rules:
  - RULE-SET,custom-domains,Proxy
  - MATCH,DIRECT

type: http tells the core to retrieve the provider over HTTP or HTTPS. behavior must agree with the file’s payload format. url identifies the remote resource, while path identifies the local cache location used by the core. interval: 86400 requests an update interval of one day, expressed in seconds. Pick an interval that suits how often the list changes and how much update traffic is reasonable; checking more frequently does not make a bad URL or malformed file valid.

The cache path is not a public GitHub path. It is a local path available to the running core, and its exact base directory can depend on how the client launches mihomo or another compatible core. Use a writable location supported by that client. If the core cannot create or update the cache file, the provider may fail even when the URL is correct. Some clients also manage configuration files or working directories themselves, so check the client’s logs and configuration handling before assuming a path is relative to the visible profile directory.

The RULE-SET line connects the provider to routing. Its provider name must exactly match the key under rule-providers. In this example, matches use the Proxy policy, and unmatched traffic reaches MATCH,DIRECT. Replace Proxy with a policy or group that actually exists in your config. If the provider contains ad domains and the intended action is to block them, use an appropriate reject policy instead of copying the example action unchanged.

Rule Order Determines the Result

Clash evaluates the rule list from top to bottom and uses the first matching rule. A provider does not get priority merely because it has its own section near the top of the YAML file; its effective position is the position of its RULE-SET reference in rules. Put exceptions and more specific rules where they can take effect before broader rules. Keep a catch-all such as MATCH at the end, because rules below a catch-all will never be reached.

For instance, if a broad provider routes a domain through Proxy, a later rule cannot override that result. If a specific domain should instead go direct, place its direct rule before the broad provider reference. If a provider is used for IP ranges, check whether the rule needs the supported no-resolve option for your intended matching behavior; do not add it automatically to every rule. The right setting depends on rule type, DNS behavior, and the core version.

Test the result by checking a connection in the client’s connection list or logs. Confirm the requested hostname, matched rule or rule provider, and selected policy. A successful provider download only confirms that the file could be retrieved; it does not prove that a particular request matched an entry or used the policy you expected.

Understand Updates and Version Control

The interval is a refresh schedule, not a promise that every edit will be visible immediately. The core may fetch the provider at startup and then refresh it according to its update logic, but exact timing and retry behavior can vary by core version and client. After changing a GitHub file, allow for the configured interval, trigger a provider update through the client if that feature is available, or restart the core to test a fresh fetch. Then inspect the logs rather than assuming that saving a Git commit has updated the running process.

Keep provider updates small and reviewable. Before adding a large domain list, check its source and license, remove duplicates where practical, and confirm that the list’s purpose matches the policy you will apply. A broad blocklist assigned to a reject action can disrupt sign-in, software updates, or embedded content. A broad proxy list can send more traffic through a remote node than intended. Treat external rule data as routing input, not as harmless text.

When you need repeatable behavior across machines, record both the main-config revision and the provider revision or URL strategy. A branch-based URL alone does not identify the exact content a device fetched last week. Conversely, pinning every provider can make maintenance cumbersome if nobody tracks when those pins should be updated. Balance convenient refreshes with the ability to explain and reproduce a routing decision.

Troubleshoot Fetch and Match Failures

When a provider does not work, identify which stage failed: configuration parsing, URL access, payload parsing, local caching, or rule matching. Fix one stage at a time. A browser opening a GitHub page is not proof that the core can retrieve the raw file, and an HTTP success response does not prove that the response body is valid provider YAML.

SymptomWhat to check
Provider name or rule reference errorCompare the name under rule-providers with the name in RULE-SET. Check YAML indentation, commas in the rule line, and whether the referenced policy exists.
Timeout, DNS failure, or connection errorConfirm that the running core can reach raw.githubusercontent.com through the current network path. Check DNS, firewall or proxy restrictions, and whether the client’s core has outbound access.
HTTP 404 or unexpected responseCheck owner, repository, branch, exact path, filename capitalization, and whether the file is publicly accessible. Use the raw-file URL, not the GitHub HTML view.
YAML parse or behavior errorConfirm that the file has a payload list, that its entries match the selected behavior, and that indentation and quoting are valid.
Provider loads but traffic is not routed as expectedCheck that the RULE-SET line is present and above any matching broader rule or MATCH. Inspect the connection’s matched rule and policy.
Updates appear stuckCheck the configured interval, the last update result in logs, the local cache path’s permissions, and whether the running core is using the config you edited.

If GitHub access is unreliable on the network where the core runs, first distinguish a host-side access problem from a YAML problem. Test the exact raw URL from the same machine and network, then inspect the core’s error log. A browser may use a different proxy path from the core, especially when the client is in rule mode or TUN is disabled. Do not repeatedly shorten the update interval as a substitute for restoring network access.

Finally, validate after each change. Confirm the config parses, the provider reports a successful load, the expected entry is present in the provider file, and a test connection matches the intended rule. If a list breaks routing, temporarily remove its RULE-SET reference or restore the previous provider revision, then retest. This isolates the effect of the provider without deleting unrelated proxy nodes, groups, or DNS settings.

Clash for Mac Download