Why use Clash rule providers for custom routing?

If your custom routing policy is a growing list of entries pasted directly into a Clash configuration, every change creates another maintenance task. You have to edit the main YAML file, remember which device has the latest copy, and repeat the work when a domain changes or a new exception is needed. A typo can also affect a much larger part of the configuration than intended. Clash rule providers offer a cleaner option: keep reusable rules in a separate file, publish that file at a stable URL, and let a compatible core such as Mihomo retrieve and refresh it.

A rule provider does not replace your proxy groups or decide which proxy server is healthy. It supplies a set of matching rules that your main configuration can reference by name. The main configuration still determines what happens when a rule matches—for example, sending a domain through a selected proxy group, choosing DIRECT, or rejecting a connection with REJECT. Keeping those responsibilities separate makes it easier to review changes and reuse the same rule set across profiles.

This guide walks through a practical setup: create a rules file, host it in a GitHub repository, declare it under rule-providers, and connect it to the main rules list with RULE-SET. It also covers update intervals, matching order, local file paths, and the checks that help distinguish a failed download from a rule that simply did not match. The examples use common Mihomo-compatible configuration conventions; client labels and supported features can vary by core version, so validate the result with the core bundled in your client.

Before changing an active profile, make a backup and note the current behavior you want to preserve. Do not publish subscription URLs, credentials, private hostnames, or other sensitive details in a public repository. A public rules file should contain only the routing entries you intend other people to read and download.

Create a rule file and host it on GitHub

Start with a small, single-purpose file. For example, you might keep domains for a development service together, or maintain an allowlist for a set of sites that should use one proxy group. Smaller files are easier to review than a broad collection of unrelated entries. Give the file a descriptive name such as developer-sites.yaml, then choose a provider behavior that matches the kinds of rules it contains.

  • domain: use domain-oriented entries when the provider is intended to match domain names. This is a natural fit for a focused list of sites or services.
  • ipcidr: use this behavior for IP addresses or network ranges written in CIDR notation. Confirm that the entries really are address ranges, rather than hostnames.
  • classical: use this for a collection that needs the broader Clash rule syntax, such as a mix of supported rule types. Check the exact syntax supported by the Mihomo version you run.

For a YAML-formatted provider, the rules file contains a payload list. A simple example looks like this:

payload:
  - DOMAIN,docs.example.com
  - DOMAIN-SUFFIX,dev.example.net
  - DOMAIN-KEYWORD,project

These entries illustrate domain-style rules; they are not a universal recipe for every behavior. Keep the file consistent with the behavior you declare in the main configuration. For a classical provider, use the rule syntax accepted by your core and confirm whether the selected provider format expects YAML or plain text. Do not assume that a file is valid simply because GitHub displays it without an error: the client must be able to parse it as a rule provider.

To host the file, create or select a GitHub repository and commit the rules file on a branch you intend to maintain. For a public repository, use the raw-file address rather than the GitHub page used to browse the file. A raw URL typically follows this pattern:

https://raw.githubusercontent.com/OWNER/REPOSITORY/BRANCH/path/to/developer-sites.yaml

Replace each placeholder with the actual owner, repository, branch, and file path. Open the resulting address in a browser or fetch it from a terminal to check that it returns the file contents directly. A URL ending in a GitHub HTML page is not a substitute for a raw file URL. Also check capitalization and the complete path: repository paths are case-sensitive in many contexts, so a link that differs by one letter may fail even if the repository page itself loads.

A public repository is convenient when the rules are intended for public use, but it makes every committed change visible. If you need private hosting, verify that your chosen delivery method can be reached by the Clash core without interactive sign-in. A browser session that is already authenticated does not prove that Mihomo can download the same file. Avoid placing tokens in a URL that may be copied into logs, screenshots, or a shared configuration.

Keep the repository history useful. Commit changes with clear messages, review the diff before pushing, and test a new version with a small set of representative domains. If you make a mistake, Git history gives you a straightforward way to identify and revert the change. For changes that could reroute many services, prefer a review step rather than editing the live rules file in a hurry.

Declare the provider and connect it to a proxy group

In the main configuration, declare the provider under rule-providers. The following example shows the important relationships; replace the URL, path, interval, and group name to match your setup:

rule-providers:
  developer-sites:
    type: http
    behavior: domain
    format: yaml
    url: "https://raw.githubusercontent.com/OWNER/REPOSITORY/BRANCH/path/to/developer-sites.yaml"
    path: ./rule-providers/developer-sites.yaml
    interval: 86400

rules:
  - RULE-SET,developer-sites,Proxy
  - MATCH,DIRECT

The provider name, developer-sites, is the identifier referenced later by RULE-SET. Keep the spelling identical in both locations. type: http tells the core to obtain the provider from a remote address, while behavior and format describe the rule set it should parse. The local path gives the core a place to store the downloaded copy. The interval is expressed in seconds in this example; 86400 represents one day.

The target after the provider name in the RULE-SET line is a policy or proxy group that exists in the rest of the configuration. In this example, matching entries go to a group called Proxy. If your configuration uses a group with another name, substitute that exact name. A provider is not itself a proxy group, and naming a provider Proxy does not create a usable route.

Rule order is essential. Clash evaluates rules from top to bottom and applies the first matching rule. Put a provider rule before a broad rule that would otherwise catch the same traffic, such as a general domain, geographic, or final-match rule. If MATCH,DIRECT appears above RULE-SET,developer-sites,Proxy, the provider may never get a chance to route those requests. Likewise, an earlier rule for a specific domain can take precedence over a broader suffix entry in the provider.

Do not add a provider near the top without considering exceptions that should remain above it. For example, if a particular host must always be direct, an explicit rule for that host can come before the provider reference. Write down the intended precedence in a short comment or in your repository documentation. This makes later edits safer when a rule set grows and someone needs to understand why one entry wins over another.

After editing the configuration, use the validation or reload function in your client, and read any parser errors before switching traffic. A client may use a Mihomo core but expose its own profile editor, update controls, and logs. In Clash Verge or Clash Verge Rev, for example, check the active profile and core logs rather than assuming that a saved edit has already reached the running core. Other clients, including Clash for Android or router-based Mihomo setups, may place those controls elsewhere.

The format field and file contents must agree. If the provider is declared as YAML, the downloaded file must be valid YAML in the form expected by the selected behavior. If you choose a text format for a supported provider, use the corresponding line-based syntax and confirm that your core version accepts that combination. When unsure, begin with one minimal entry and verify it loads before adding more rule types.

Manage updates, local paths, and failed matches

The update interval controls how often a remote HTTP provider is refreshed; it is not a guarantee that a change appears immediately after you push a commit. A long interval reduces unnecessary requests but means clients can keep using an older copy until the next refresh. A shorter interval can be useful while testing, but very frequent polling is usually unnecessary for a rules file that changes only occasionally. Choose an interval that reflects how quickly the rules need to change, then use the client’s provider update or configuration reload action when you want to test a new commit right away.

Remember that each device may have its own downloaded copy and refresh schedule. Updating the GitHub file does not necessarily update every running client at once. When checking a change, identify which profile and core are active, trigger an update if the client supports it, and inspect the provider status or logs. If a client reports a successful download but traffic still follows the old path, first determine whether the provider was refreshed and then check the rule order and the actual hostname being matched.

The local path is the provider cache location used by the core. A relative path such as ./rule-providers/developer-sites.yaml is commonly used, but the precise working-directory behavior can depend on how the client launches Mihomo and where the configuration is stored. Do not assume that a path on your laptop is automatically available inside a container or on a router. Confirm that the core can create or write to the directory. If you move profiles between machines, keep the relative path and folder structure consistent, or choose a path appropriate for each environment.

A local provider is useful when you want to test rules without relying on a remote download, or when the rules are generated by a process you control. In that case, use the provider type and path supported by your core, put the file where that core can read it, and reload the profile after editing. Local files avoid remote availability issues, but they also need a deliberate distribution and update process if several devices use the same policy.

When a provider fails, work through the evidence in order rather than changing several settings at once:

  • Check the raw URL: fetch it directly and confirm that the response contains the intended file, not an HTML page, a sign-in screen, or a not-found message.
  • Check reachability from the core: a URL opening on your browser does not prove the client process can reach it. Review Mihomo logs and consider whether the core’s network path, DNS, or startup timing differs.
  • Check parsing: verify YAML indentation, the payload structure, provider behavior, and format. Start with one simple valid entry if the error message is vague.
  • Check the local path: confirm that the directory exists or can be created, that the core has write permission for an HTTP cache, and that the expected file is not an old copy.
  • Check the reference: compare the provider key in rule-providers with the name used after RULE-SET. A near-match is still a mismatch.
  • Check precedence: inspect earlier rules and identify the final policy that actually matched the request. A loaded provider cannot override a rule that already matched above it.

Unexpected routing often comes down to a difference between the rule you intended and the request the core actually evaluated. A browser may connect to a hostname different from the one in your list because of redirects, an API subdomain, or a content delivery network. Look at the connection or log entry for the actual destination, then add the narrowest appropriate rule. Avoid adding a broad keyword or suffix rule until you understand what else it could match; overly broad entries can route unrelated services and make diagnosis harder.

When you change a rule, test both the intended match and a nearby non-match. If dev.example.net should use the proxy, confirm that it does. Then test a domain that merely contains similar text or belongs to a different subdomain family. This catches accidental overmatching before the file is shared across profiles. Keep an eye on the selected group as well: a rule can match correctly while the group itself selects an unavailable or unsuitable node.

Compared with editing a long rules list into every profile, a provider maintained in GitHub gives you reviewable history, a single source of truth, and controlled refreshes; the trade-off is that remote access, parsing, and rule precedence all need to be checked. Some simpler proxy clients offer fewer ways to split policies or inspect why a request matched, while a Clash-compatible Mihomo setup lets you organize reusable rule sets and direct each match to an explicit group. If that control is useful for your workflow, you can choose a compatible client from the download page.

Download Clash →