HANDBOOK / ADVANCED CONFIG

Clash Advanced Configuration Handbook

Proxy groups, rule providers, DNS, TUN with Fake-IP, domain sniffing, override merging, and external control — each topic gets its own chapter. This page is built for reference lookup, not a quick-start walkthrough.

The division of labor between this page and the User Guide is deliberate: the guide handles the main path — installing the client, importing a subscription, choosing a mode, verifying connectivity — follow it step by step and you're online. This page picks up where the main path leaves off. When the default configuration isn't enough, when a subscription update wipes out your manual edits, when a specific domain refuses to take the policy it should — the answer is usually in one of the seven chapters below.

The handbook is written against the mihomo core (the Clash Meta lineage) configuration fields, and every example is YAML you can paste and adapt directly. On desktop, we recommend reading alongside Clash Verge Rev or Clash Plus, since both let you edit and override configuration files directly; if you haven't installed a client yet, start at the client download page. Every chapter heading has its own anchor, so you can bookmark a specific section and come back to it.

Where to Look on This Site

  • guide.htmlQuick-start main path: from importing a subscription to verifying connectivity, start to finish.
  • download.htmlInstallers and core downloads for every platform.
  • wiki.htmlTerm lookup: every concept mentioned in the chapters below is defined in the glossary.
  • questions.htmlError messages and troubleshooting, organized by problem category.

Proxy Group Types in Practice

Proxy groups sit right in the middle of the configuration file: rules decide "which type of traffic goes to which group," and proxy groups decide "which node this group uses right now." Whether your traffic splitting works smoothly usually comes down to whether the proxy group structure is well designed. The mihomo core supports five basic types, and their behavior differs as follows.

How the Five Types Behave Differently

typeBehaviorTypical Use
selectManual selection; the chosen item persists until you switch it again manuallyMain entry group, region selection group
url-testPeriodically tests latency and auto-switches to the lowest-latency nodeEveryday traffic that's speed-sensitive
fallbackTakes the first node in the list that passes a health check; switches back automatically once an earlier node recoversPrimary/backup structure to keep service uninterrupted
load-balanceSpreads connections across multiple nodes by hashing or round-robinHigh-concurrency connections, download-heavy traffic
relayTraffic passes through each node in the list in order, forming a chainChained proxying, special network path requirements

select is the most commonly used type and also the most underrated: it makes no automatic decisions at all, and precisely because of that its behavior is fully predictable — well suited as the "human-decided" main entry point. The difference between url-test and fallback is often confused: the former always chases "fastest right now," which can cause frequent flip-flopping when nodes are unstable; the latter chases "the highest-priority node that's still available," only moving when the current node actually fails, prioritizing stability. For interactive applications (remote desktop, voice calls), fallback usually feels better than url-test, because switching means the connection has to be rebuilt.

Three Key Parameters for url-test

An auto speed-test group's behavior is governed by three parameters. interval is the test cycle in seconds; 300 is a common value — set it too short and you'll generate a flood of probe requests, which also drains battery on mobile. tolerance is the margin in milliseconds: a new "fastest" node must beat the current node by at least this much before a switch is triggered; starting at 50 noticeably reduces pointless flip-flopping. When lazy is set to true, the group skips testing while no traffic is passing through it, which can save a meaningful amount of probing overhead for configurations with many nodes.

A Practical Grouping Structure

The recommended structure has three layers: a single select group as the top-level entry, mid-level groups organized by region or purpose, and individual nodes only at the bottom. Rules should always point at the top or mid-level groups, never directly at nodes — that way switching providers or renaming nodes never requires touching a rule. Example:

proxy-groups:
  - name: Node Selection
    type: select
    proxies: [Auto Speed-Test, Fallback, Hong Kong Nodes, Japan Nodes, DIRECT]

  - name: Auto Speed-Test
    type: url-test
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50
    lazy: true
    proxies: [HK-01, HK-02, JP-01]

  - name: Fallback
    type: fallback
    url: https://www.gstatic.com/generate_204
    interval: 300
    proxies: [HK-01, JP-01, SG-01]

  - name: Hong Kong Nodes
    type: url-test
    url: https://www.gstatic.com/generate_204
    interval: 300
    proxies: [HK-01, HK-02]
Tip

Pick a lightweight endpoint that returns a 204 status (like generate_204 above) for health checks — the response body is empty and overhead is minimal. Don't use a full webpage for testing; that measures page load time, not link latency.

Rule-Provider Subscriptions

Writing hundreds or thousands of rules directly into the main configuration is the start of a maintenance nightmare: every subscription update means starting over, and adjusting a single rule means hunting through a massive file. Rule providers split rules into independent remote files, leaving only a reference in the main configuration; rule content updates automatically on a schedule, and the main config stays a tidy dozen-or-so lines.

The Three behavior Types

Every rule provider must declare a behavior, which determines how the file content is parsed — the three types cannot be mixed. A domain-type file can only contain domain names (supporting the +. wildcard prefix) and matches fastest; ipcidr can only contain IP ranges (CIDR notation); classical allows full rule syntax (DOMAIN-SUFFIX, IP-CIDR, DST-PORT, and more, mixed together) — flexible, but with slightly higher matching overhead. The principle: use domain or ipcidr whenever you can, and reserve classical for cases that genuinely need mixed conditions.

format and Update Interval

format supports yaml, text, and mihomo's own binary format, mrs. mrs is precompiled — small and fast to load — and is the better choice for large domain/IP sets (like an entire region's IP database); small, hand-maintained rule sets are fine as yaml or text. interval controls the auto-update cycle in seconds; since rule-provider content doesn't change often, 86400 (one day) is a reasonable value — there's no need to be more aggressive.

rule-providers:
  streaming:
    type: http
    behavior: classical
    format: yaml
    url: https://example.com/rules/streaming.yaml
    path: ./rule-sets/streaming.yaml
    interval: 86400
  cn-ip:
    type: http
    behavior: ipcidr
    format: mrs
    url: https://example.com/rules/cn-ip.mrs
    path: ./rule-sets/cn-ip.mrs
    interval: 86400

rules:
  - RULE-SET,streaming,Node Selection
  - RULE-SET,cn-ip,DIRECT
  - MATCH,Node Selection

The reference syntax is RULE-SET,provider-name,policy. Note that rules are still matched top-to-bottom and stop on the first hit, so the ordering of RULE-SET entries matters just as much as ordinary rules: put high-hit-rate sets first, and place IP-based rule sets after domain-based ones (IP rules trigger DNS resolution, and triggering it earlier than necessary is wasted work). The MATCH catch-all rule always goes on the last line.

Note

A mismatch between the declared behavior and the file's actual content is the most common rule-provider failure — for example, declaring a file written in classical syntax as domain will cause the core to error out or the whole set to silently fail. When referencing a third-party rule provider, confirm the behavior type stated by the publisher before copying it.

DNS Configuration Tuning

DNS is the foundation of traffic-splitting quality. If domain resolution is poisoned, IP-based rules end up making decisions based on the wrong IP; if the resolver is chosen poorly, direct traffic takes a longer path and CDN requests land on slow nodes. The core ships with a complete DNS module, and once you understand what each field is responsible for, most "the rule is clearly written correctly but it's not working" problems resolve themselves.

The Division of Labor Between nameserver and default-nameserver

nameserver is the primary resolver list, responsible for resolving all business domains; using DoH (DNS over HTTPS) addresses is recommended to avoid interference on plain port 53. There's a chicken-and-egg problem here: a DoH address is itself a domain name that needs resolving — that's exactly what default-nameserver is for. It's only responsible for resolving the domains that appear in the nameserver list, and it must be filled with plain-IP traditional DNS servers. The two have distinct roles and can't substitute for each other.

Per-Domain Dispatch with nameserver-policy

nameserver-policy lets you assign a dedicated resolver by domain pattern: domains inside mainland China go through a mainland DNS server to get the nearest CDN, while everything else goes through a trusted encrypted DNS to avoid poisoning. It supports geosite category references, so a single line can cover an entire class of domains — this is currently the recommended split-resolution approach, more intuitive and more predictable than the old fallback + fallback-filter combination.

dns:
  enable: true
  listen: 0.0.0.0:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://doh.pub/dns-query
    - https://dns.alidns.com/dns-query
  nameserver-policy:
    "geosite:cn":
      - https://doh.pub/dns-query
    "geosite:geolocation-!cn":
      - https://dns.cloudflare.com/dns-query

enhanced-mode determines the enhanced resolution mode, taking the value fake-ip or redir-host; how it works together with TUN is covered in the next chapter. listen is the address the core's DNS listens on — under TUN mode, it works with dns-hijack to redirect system DNS queries here, ensuring all resolution passes through the core.

Tip

The most direct way to verify DNS is working correctly is to check the resolved IP ownership in the connections panel: mainland sites resolving to mainland CDNs, and no obviously abnormal IPs showing up for other sites, generally means it's configured correctly. If resolution behaves oddly, check first whether default-nameserver is reachable.

TUN and Fake-IP

System proxy mode has a built-in weakness: it only governs "programs that respect the system proxy setting." Command-line tools, games, and some client software simply don't read the system proxy at all. TUN mode creates a virtual network interface on the system and pulls all traffic into the core at the network layer, fixing the incomplete-coverage problem at the root. UWP apps' loopback restrictions, and git or package managers in a terminal, no longer need special handling under TUN mode.

Enabling TUN and Choosing a stack

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

auto-route automatically takes over system routing, and auto-detect-interface automatically identifies the physical outbound interface — both are usually left on. dns-hijack redirects queries sent to any port 53 to the core's DNS, a key piece of how TUN and Fake-IP work together. stack determines the virtual interface's protocol stack implementation: system uses the OS network stack directly and offers good throughput; gvisor is a userspace implementation with good compatibility; mixed splits the difference, sending TCP through system and UDP through gvisor — a reasonable starting point on desktop. Prerequisites for enabling TUN differ by platform:

PlatformPrerequisiteNotes
WindowsRun as administrator, or install the client's system serviceClash Verge Rev offers a service mode to avoid elevating every time
macOSFirst activation requires entering an administrator password to authorizeOnce authorized, it works silently afterward
AndroidUses the system VpnService interface; just authorize the VPN connectionNo root needed; see the tip below for background policy
LinuxRoot privileges, or grant the binary the CAP_NET_ADMIN capabilityFor server use, running as a persistent systemd service is recommended

How Fake-IP Works, and fake-ip-filter

Fake-IP is a resolution strategy paired with TUN: when a program issues a domain query, the core doesn't wait for real resolution to finish — it immediately returns a "fake IP" from a reserved range (198.18.0.1/16 by default) and remembers the mapping. When a connection arrives, the core looks up the domain from the fake IP and matches it directly against domain-based rules — skipping a serial DNS wait, speeding up connection setup, and making rule matching more accurate. The tradeoff is that some programs break when they get a fake IP: LAN discovery, time sync, and connectivity checks — anything that takes the IP at face value — need to be exempted, which is what fake-ip-filter is for:

dns:
  fake-ip-filter:
    - "*.lan"
    - "+.local"
    - "time.windows.com"
    - "+.msftconnecttest.com"
    - "+.stun.*.*"

Domains that match the filter list get real resolution and a real IP. Keep the list minimal — the more entries you add, the more Fake-IP's benefit gets diluted. Also note that switching between Fake-IP and redir-host can leave stale resolution caches in the system and browser, which shows up as odd behavior on some sites for a while; restarting the client or flushing the system DNS cache fixes it.

Note

Keeping TUN on long-term has a noticeable impact on mobile battery life — the tradeoffs between background keep-alive and manufacturer power-saving policies are covered in the blog post "Diagnosing Abnormal Battery Drain from Clash on Android"; issues like crash-on-launch or TUN failing to enable on desktop are covered item by item in the troubleshooting section of Common Questions.

Domain Sniffing

Domain-based rules are the easiest to write, but two kinds of traffic arrive at the core with only an IP and no domain: first, programs that resolve DNS themselves and connect directly to the IP (bypassing the core's resolution step entirely); second, cases outside the Fake-IP mapping. Without a domain, DOMAIN-SUFFIX and similar rules simply can't match, and the traffic falls through to IP-based rules or the catch-all. Domain sniffing (sniffer) works by "reading" the domain back out of the traffic itself: the TLS handshake's SNI field, the HTTP request's Host header, and QUIC's handshake packets all carry the target domain. The core parses these protocol features early in connection setup and feeds the recovered domain back into the rule engine.

Configuration Structure

sniffer:
  enable: true
  sniff:
    HTTP:
      ports: [80, 8080-8880]
      override-destination: true
    TLS:
      ports: [443, 8443]
    QUIC:
      ports: [443]
  force-domain:
    - "+.example-cdn.net"
  skip-domain:
    - "+.push.apple.com"

Under sniff, port ranges to sniff are declared per protocol — only declared ports get sniffed, and the narrower the range, the lower the overhead. override-destination determines whether the sniffed domain overrides the connection's destination address — once enabled, the connection continues to be handled as a domain, with both rule matching and DNS dispatch going by domain. force-domain forces sniffing overrides for matched domains, commonly used for apps that connect directly to an IP even after receiving a Fake-IP; skip-domain is the whitelist — matched domains skip the override, and it's worth listing long-lived connections that are sensitive to their destination, like push services, to avoid sniffing interference.

Note

Sniffing isn't decryption: it only reads the plaintext metadata carried during the protocol handshake (SNI, Host) and never touches the encrypted payload. For most configurations, enabling HTTP and TLS sniffing already covers the main cases; add QUIC only if you need it.

Local Overrides and Multi-Subscription Merging

Editing the configuration file delivered by a subscription directly is the most common maintenance trap for newcomers: the next subscription update overwrites the whole thing with the provider's template, and every manual edit vanishes instantly. A good chunk of the cases in the blog post "Troubleshooting a Failed Clash Subscription Update" trace back to exactly this. The right approach is to separate "what the provider gives you" from "what you write yourself": treat the subscription purely as a node source, and put personalized content into an override layer or a separate provider.

Client Overrides: Merge and Script

Clash Verge Rev offers two tiers of overrides, both applied after the subscription updates and before the core loads the config, so they're never wiped out by a subscription. Merge overrides are declarative: you write a YAML snippet, and its fields merge into the final configuration — suited to structural additions like extra DNS settings, rule providers, or a few custom rules pinned to the top. Script overrides are a JavaScript function that receives the full configuration object and returns a modified one — suited to cases that need logic, like filtering nodes by name with a regex, bulk-adding nodes to proxy groups, or dynamically generating groups based on node count. The two can be combined; Merge is recommended by default, and reach for Script only when you genuinely need programmatic control. Clash Plus also offers a way to keep subscriptions and local configuration separate; see Client Comparison for how the clients differ on this front.

proxy-providers for Multi-Subscription Merging

If you hold subscriptions from multiple providers, there's no need to switch configurations back and forth. proxy-providers declares each subscription as its own node source, updated independently, and the use field on a proxy group pulls nodes from multiple sources into a single group:

proxy-providers:
  airport-a:
    type: http
    url: https://a.example.com/sub?token=xxxx
    path: ./providers/airport-a.yaml
    interval: 43200
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 600
  airport-b:
    type: http
    url: https://b.example.com/sub?token=xxxx
    path: ./providers/airport-b.yaml
    interval: 43200

proxy-groups:
  - name: Node Selection
    type: select
    use: [airport-a, airport-b]
  - name: Auto Speed-Test
    type: url-test
    url: https://www.gstatic.com/generate_204
    interval: 300
    use: [airport-a, airport-b]

use and proxies can coexist in the same group — the former pulls in every node from the listed providers, and the latter appends hand-written nodes or other groups. health-check gives a provider its own built-in testing, and url-test groups referencing it can reuse those results directly. interval is the subscription pull cycle in seconds; 43200 (half a day) is plenty for most providers, and a failed pull from one provider doesn't affect the others — one of the natural resilience benefits of a multi-subscription structure.

Tip

A provider's filter field (a regex) lets you admit only specific nodes into a group — filtering by region name, for instance — and combined with use, you can build a structure that aggregates same-region nodes from multiple providers for speed testing, entirely transparent to the rule layer.

External Controller Panel

At runtime, the core exposes a RESTful control API — node switching, latency testing, connection inspection, and config reloading all go through it, and desktop client UIs are essentially wrappers around this same API. Using the external controller directly matters in two scenarios: running a bare core on a router or server with no GUI, and wanting to manage things through a browser panel or automation script.

Enabling the Interface and Authentication

external-controller: 127.0.0.1:9097
secret: "your-strong-secret"
external-ui: ./ui

external-controller declares the listen address and port. Bind it to 127.0.0.1 for local use only; bind it to 0.0.0.0 only when another device on the LAN needs access (like managing a router's core from your phone), and in that case secret must be set to a sufficiently strong random string — every request must carry it in the Authorization header. external-ui points to a directory of static web-panel files that the core will host directly; open the control address in a browser and it just works. Popular open-source web panels (the metacubexd and yacd families) can simply be unzipped into that directory.

Automating with the API

The interface is standard HTTP + JSON, and curl alone can drive it. Viewing every proxy group and node status:

curl -H "Authorization: Bearer your-strong-secret" http://127.0.0.1:9097/proxies

Switching the selected node in a select group by sending a PUT request to the group name:

curl -X PUT -H "Authorization: Bearer your-strong-secret" -d '{"name":"HK-01"}' http://127.0.0.1:9097/proxies/Node Selection

Other commonly used endpoints include /connections (a live connection list — the first place to check "which policy did this traffic actually take"), /logs (a log stream), and /configs (changing the port or mode at runtime). Wire these endpoints into a script and you can build unattended logic like scheduled speed tests or automatic failover.

Note

The control interface has full control over the core. Binding a non-loopback address without setting a secret is equivalent to opening up proxy control to your entire LAN; exposing it to the public internet is never acceptable under any circumstances. The secret in the example is a placeholder — replace it with your own randomly generated value before actual use.

Reading Path and Further Reading

The seven chapters have a clear dependency structure: proxy groups and rule providers form the skeleton, DNS is the foundation, TUN, Fake-IP, and sniffing solve "how completely traffic is captured and how accurately it's matched," overrides and merging solve long-term maintenance, and the external controller handles runtime observation and automation. Jump into whichever chapter addresses your actual pain point — there's no need to read start to finish. If you run into an unfamiliar term while configuring, the glossary defines terms across five categories: core & client, proxy protocols, rules & proxy groups, DNS & traffic processing, and configuration fields; if you hit an error or odd behavior after changing your configuration, check the troubleshooting section of Common Questions first; if you still haven't decided which client to use for these configurations, Client Comparison offers recommendations by platform and usage habits, and the full first-install checklist is in the blog post "First-Run Setup Checklist for the Clash Client". This page will keep being revised as core configuration fields evolve, so it's worth bookmarking for reference.