CONFIG REFERENCE

Clash Config File Reference

A single YAML file controls everything Clash does: which port it listens on, which node it routes through, which traffic connects directly, and how domains get resolved. This page breaks the config file down section by section, following its actual structure, with a ready-to-use example for each part — built as a reference to keep coming back to after installation.

If you haven't finished installing Clash or importing a subscription yet, start with the getting started guide to walk through the basics first, then come back here for the details. Need an installer? Head to the download page for clients on every platform. This page is written for users who already have a working connection and want to understand — and edit — their config file directly.

mihomo core · YAML · rule-based

1. What This Page Covers & the YAML Structure

Clash-family clients — and mihomo, the core that actually runs underneath — read a YAML config file to determine every bit of behavior. A subscription link is, at its core, a config file hosted on a server that you can re-fetch anytime. Every toggle you see in a client's UI ultimately maps to a field in this same file. Once you understand its structure, you understand the relationship between your subscription content, the client's settings, and the core's logs all at once — no more clicking through menus at random when something breaks.

This page splits the work with the getting started guide along the lines of "quick setup" vs. "deep reference": the guide walks you through one complete run from importing a subscription to confirming you're online, while this page systematically answers "what does this field mean, and what else can I put here?" outside of that flow. Treat the two as complements — when the guide glosses over a field, jump to the matching section here using the table of contents above.

Top-Level Structure: Five Main Blocks

A complete config file breaks down into roughly five blocks. Their order in the file doesn't affect how it's parsed, but almost every subscription follows the order below — useful to know when you're skimming someone else's config and need to find something fast:

BlockPurposeTypical Fields
General fieldsGlobal behavior: ports, running mode, logging, LAN sharing, and moremixed-portmodelog-level
dnsHow the core handles domain resolution, including Fake-IPenhanced-modenameserver
proxiesLists every available proxy node and its protocol parameterstypeserverport
proxy-groupsOrganizes nodes into selectable, speed-testable proxy groupstype: selecturl-test
rulesMatches traffic in order to decide which proxy group handles itDOMAIN-SUFFIXGEOIPMATCH

Three Hard Rules of YAML Syntax

YAML is extremely sensitive to formatting, and nine out of ten config errors are syntax problems, not field problems. Remember three rules before you start editing: first, indentation must use spaces only — a single Tab character is enough to break parsing for the whole file, and the reported error line often points somewhere further down, making it easy to miss; second, a colon must be followed by a space, so port:7890 is invalid while port: 7890 is correct; third, if a node name contains emoji, a hash symbol, quotes, or starts with a special character, wrap the whole string in double quotes, or it may get parsed as a comment or syntax token. A # at the start of a line marks a comment — when debugging, prefixing a rule with a hash to disable it temporarily is safer than deleting it outright. If you're unsure about a term, check the "Subscriptions & Configuration" category in the glossary.

2. General Fields: Ports, Modes & Runtime Options

General fields sit at the top level of the file, outside any indented block, and determine how the core behaves overall. Here's a minimal working config you can use as a starting point:

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false
external-controller: 127.0.0.1:9090

The Port Family: mixed-port and Friends

mixed-port is the most commonly used port field today — it accepts both HTTP and SOCKS5 inbound connections on a single port, so you can point your system proxy at it without separate settings. The older port (HTTP only) and socks-port (SOCKS5 only) fields still work and are handy when you need to hand each protocol to a different app. There's also redir-port and tproxy-port, meant for transparent proxying on Linux and router setups — regular desktop users can skip these entirely. Stick to port numbers above 1024, the reserved system range. If the log shows bind: address already in use on startup, another process (often a leftover proxy instance) is already using that port — pick a different one or close the conflicting process.

mode: Three Running Modes

ValueBehaviorWhen to Use
ruleEvery connection is matched against the rules block, in order, to decide routingEveryday default — balances speed and accuracy
globalIgnores all rules; every connection uses one globally selected proxyQuickly testing whether a specific node works
directAll traffic connects directly, bypassing every nodeFiguring out whether an issue is proxy-related at all

The Rule/Global/Direct toggle in a client's UI is exactly this field. When troubleshooting, switch to direct first to confirm your local network is fine, then global to confirm a node works, and finally back to rule to check your rules — this three-step process is the fastest way to isolate a problem.

Other Frequently Used Fields

Setting allow-lan to true lets other devices on the LAN point their gateway at this machine's proxy port — handy for sharing the proxy with a smart TV or game console. When enabled, it's worth pairing it with bind-address to limit which network interface is listening, so you're not exposing the port to strangers on a public network. log-level ranges from most to least verbose: debug, info, warning, error, silent. Bump it to debug temporarily to see exactly which rule each connection matched. external-controller opens a RESTful API for dashboard-style tools to read status and switch nodes; if a secret field is set, requests must include that same key — always use a dummy value like secret: "xxxx" in examples. ipv6 is off by default, and turning it on in a network with incomplete IPv6 support tends to introduce resolution timeouts rather than fix anything.

3. The DNS Block: Resolution Modes & Fake-IP

A lot of "my rule is definitely right but isn't working" or "some sites work, some don't" problems trace back to DNS. The reason the core ships its own DNS setup is that routing rules rely heavily on domain names and geolocation — if resolution gets tampered with or bypasses the core entirely, everything downstream is matching against the wrong answer. Here's a common DNS block:

dns:
  enable: true
  listen: 0.0.0.0:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - "*.lan"
    - "+.local"
  nameserver:
    - https://223.5.5.5/dns-query
  fallback:
    - https://1.1.1.1/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN

enhanced-mode: fake-ip vs. redir-host

In fake-ip mode, the core doesn't actually resolve a domain query — it hands back a placeholder address from the reserved range set in fake-ip-range (default 198.18.0.1/16) and remembers which domain that placeholder maps to. When an app later connects to that placeholder, the core looks up the real domain from its mapping and runs rule matching against it. The upside: no resolution delay, and domain-based rules match almost perfectly. The downside: anything that depends on a real IP — LAN device discovery, some game matchmaking, verification services that need to see your actual IP — will break because it only ever sees the placeholder. That's exactly what fake-ip-filter is for: domains listed there skip the placeholder logic entirely and get a real resolved address. redir-host mode always returns the real IP, so it's more compatible but takes a longer path to resolve. For a full comparison of how both modes actually work, see the blog post "What Is Fake-IP Mode".

nameserver vs. fallback

nameserver is your default upstream — usually a geographically close, fast-responding server. fallback is the backup, used when fallback-filter flags the default result as suspicious (for example, when geoip: true is set and a domain outside your country resolves to a local IP anyway). Upstream addresses support four formats: plain IP (UDP 53), tls:// (DoT), https:// (DoH), and quic:// (DoQ) — the encrypted formats help prevent resolution requests from being tampered with in transit. Make sure at least one entry in nameserver can be resolved without going through the proxy, or you'll hit a chicken-and-egg problem: resolving the proxy server's own domain also needs DNS.

NoteAfter switching enhanced-mode or changing fake-ip-range, your system and browser may still be holding onto old resolution results — which can look like the change broke your connection entirely. Restart the client and flush your system's DNS cache (on Windows, run ipconfig /flushdns) before checking again.

4. Proxy Node Fields: proxies Explained

proxies is a list where each entry describes one node. In everyday use with a subscription, this section is generated by the subscription server and you'll rarely write it by hand — but understanding it pays off in two ways: you can diagnose connection issues at the field level (wrong port, missing transport parameters, mismatched encryption), and you can add a self-hosted node temporarily without needing a conversion tool. Every protocol shares four base fields: name (a unique identifier used when referencing this node elsewhere — duplicates will break parsing), type (protocol), server, and port. udp: true tells the node to also forward UDP traffic, which voice calls and games rely on.

Field Shapes for Three Common Protocols

proxies:
  - name: "Example-SS"
    type: ss
    server: node1.example.com
    port: 8388
    cipher: aes-128-gcm
    password: "your-password"
    udp: true

  - name: "Example-VMess"
    type: vmess
    server: node2.example.com
    port: 443
    uuid: 00000000-0000-0000-0000-000000000000
    alterId: 0
    cipher: auto
    tls: true
    network: ws
    ws-opts:
      path: /ws
      headers:
        Host: node2.example.com

  - name: "Example-Trojan"
    type: trojan
    server: node3.example.com
    port: 443
    password: "your-password"
    sni: node3.example.com

For Shadowsocks (ss), cipher and password must match the server exactly — get the encryption method one letter off and the connection just fails silently. VMess uses uuid as its credential, and alterId is fixed at 0 under the current protocol version. network determines the transport layer: set it to ws and you'll need matching ws-opts specifying the path and Host header, or grpc with matching grpc-opts. Trojan always runs over TLS, so if sni doesn't match the certificate's domain, the handshake gets rejected outright — for test environments with self-signed certs you can add skip-cert-verify: true, though it's not recommended for real use.

mihomo Protocol Extensions

As the leading core in use today, mihomo supports newer protocols beyond the classics above — VLESS, Hysteria2, TUIC — each with its own field set (Hysteria2's up/down bandwidth declarations, for instance). Whether these work depends on the core version bundled with your client, which is one reason the client comparison page recommends prioritizing mihomo-based clients (like Clash Plus for every platform, or Clash Verge Rev on desktop): older cores just throw "unsupport proxy type" and refuse to load the entire config when they hit a node using a newer protocol.

5. Proxy Group Fields: The Four Types of proxy-groups

If proxies is the raw material, proxy-groups is the layer that organizes it into decision units: rules don't point directly at a node, they point at a group, and the group's own logic — manual selection or automatic latency testing — decides the actual exit node. This design means switching nodes never requires touching a single rule. Here's how the four group types behave:

typeHow It DecidesKey Fields
selectYou pick manually from the client UIproxies
url-testTests latency on a schedule and auto-picks the fastest memberurlintervaltolerance
fallbackUses the first available member in list orderurlinterval
load-balanceSpreads connections across multiple membersstrategy
proxy-groups:
  - name: "Select Node"
    type: select
    proxies:
      - Auto Speed Test
      - Example-SS
      - Example-VMess
      - DIRECT

  - name: "Auto Speed Test"
    type: url-test
    url: http://cp.example.com/generate_204
    interval: 300
    tolerance: 50
    lazy: true
    proxies:
      - Example-SS
      - Example-VMess

Field Details & Nesting Tricks

For auto-testing groups, url should point to a lightweight endpoint that returns a 204 status (every client ships with a default test URL, so you can usually leave it blank). interval sets the retest cycle in seconds — 300 is a common value. tolerance is the switching threshold: if the latency difference between the current and a faster node is smaller than this value in milliseconds, the group won't switch, which prevents two similarly-fast nodes from flip-flopping and constantly resetting your connection. lazy: true skips speed testing while the group isn't in active use, which noticeably cuts background traffic when you have a lot of nodes. A group's members can be node names, other group names, or the built-in policies DIRECT and REJECT — which means you can nest a manual group around an auto group: leave "Auto Speed Test" running day-to-day, and manually pin a specific node when you need to. The one thing to avoid is two groups referencing each other in a loop — the core will reject the config at startup if it detects one. Group names must also be globally unique and get referenced verbatim by rules, so if you rename a group, update every rule that points to it.

6. Rule Syntax: How rules Matches Traffic

rules is where routing decisions actually get made. Every time a new connection comes in, the core checks the list from top to bottom — the first match wins, and nothing after it gets evaluated. That means the order you write rules in is the priority itself; shuffle the same rules around and you can get a completely different routing outcome. Every rule follows the same general format, type,match value,policy, where the policy can be a group name, a node name, or the built-in DIRECT/REJECT:

rules:
  - DOMAIN,dl.example.com,Select Node
  - DOMAIN-SUFFIX,example.org,Select Node
  - DOMAIN-KEYWORD,tracker,REJECT
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR6,fd00::/8,DIRECT,no-resolve
  - GEOSITE,cn,DIRECT
  - GEOIP,CN,DIRECT
  - RULE-SET,ads,REJECT
  - MATCH,Select Node

Rule Type Reference

TypeMatches AgainstNotes
DOMAINExact domain matchMost precise — matches exactly one domain
DOMAIN-SUFFIXDomain suffixMatches the domain and all subdomains — the most commonly used type
DOMAIN-KEYWORDDomain contains keywordWidest reach, easy to over-match — use sparingly
IP-CIDR / IP-CIDR6Destination IP rangeSee no-resolve below for pairing it correctly
GEOIPDestination IP's geolocationRelies on the GeoIP database
GEOSITEDomain category databaseRelies on the GeoSite database
PROCESS-NAMEName of the process making the connectionPer-app routing on desktop
RULE-SETExternal rule setReferences a set defined in rule-providers
MATCHMatches unconditionallyThe catch-all rule — must always be last

no-resolve & Ordering Principles

IP-based rules resolve the domain to an IP by default before comparing — but if a rule is really only meant to catch traffic that was already an IP to begin with (a LAN subnet, say), that resolution is a pure waste, and it can slow down every matching connection. Appending no-resolve to the end of the rule tells it to skip straight past when the target is a domain. As for ordering, follow two principles: put precise, low-cost checks first (the DOMAIN family), and anything that needs resolution or a database lookup later (GEOIP); put reject rules as early as possible so ad requests get blocked before they reach heavier matching logic. How accurate GEOSITE and GEOIP are depends entirely on how current your local database is — letting it go stale is a common, quiet cause of misrouted traffic. See "What to Do When Your GeoIP or GeoSite Database Is Out of Date" for update instructions.

Debug TipTo see which rule a specific connection matched, temporarily set log-level to debug, or check the connections panel in your client, which usually labels each active connection with the rule that routed it — far faster than guessing rule by rule.

7. Providers & Rule Sets: proxy-providers and rule-providers

Writing hundreds of nodes and tens of thousands of rules directly into your main config makes it bloated and hard to update. Providers pull that content out into external resources that get fetched, cached, and refreshed on their own schedule — your main config just references them, while the actual content lives remotely. This is the standard shape of modern subscriptions: your subscription link is, in effect, a node list in the proxy-providers sense.

proxy-providers: Hosting Your Node Source

proxy-providers:
  main:
    type: http
    url: "https://sub.example.com/subscribe?token=xxxx"
    path: ./providers/main.yaml
    interval: 3600
    health-check:
      enable: true
      url: http://cp.example.com/generate_204
      interval: 600

type: http pulls from a remote source, paired with a url and a local cache path in path; type: file reads straight from a local file, which works well for a hand-maintained list of self-hosted nodes. interval controls how often it re-fetches, in seconds, and health-check has the core periodically test nodes in the list so proxy groups can filter by availability. To let a proxy group pull nodes from a provider, use the use field alongside (or instead of) proxies:

proxy-groups:
  - name: "Subscription Nodes"
    type: url-test
    use:
      - main
    url: http://cp.example.com/generate_204
    interval: 300

rule-providers: Hosting Your Rule Sets

rule-providers:
  ads:
    type: http
    behavior: domain
    format: yaml
    url: "https://sub.example.com/rules/ads.yaml"
    path: ./ruleset/ads.yaml
    interval: 86400

The easiest mistake to make with rule sets is a mismatch between behavior and the actual file contents. It takes three values: domain (the file is all domains), ipcidr (all IP ranges), and classical (every line is a full "type,value" rule). Declare a domain list as classical by mistake and it'll load fine — with zero errors — but never match anything, which makes it a nasty one to debug. format supports yaml and text, and mihomo also supports the smaller, faster-loading binary mrs format. Once declared, a set gets pulled into the main rule table with a line like RULE-SET,ads,REJECT — updating the rule set never requires touching your main config again, which is exactly where the long-term value lies. The token=xxxx in the example is a placeholder; use the full link your subscription service actually gives you.

8. Override & Merge: Keeping Subscription Updates From Wiping Out Your Edits

Editing a subscription's config file directly has one fatal flaw: the next time it auto-updates, the remote content overwrites your local file wholesale, wiping out every rule you added and every DNS tweak you made. Override and Merge exist to solve exactly this — they keep "your changes" and "the subscription's content" stored separately, and the client re-applies your changes automatically every time the subscription updates. Before editing anything, check which mechanism your client actually supports:

ClientMechanismNotes
Clash Plus (recommended)Override ConfigA consistent override entry point across every platform, mounted per subscription
Clash Verge RevMerge + ScriptDeclarative YAML merge, with scripting available for more complex logic
FlClashOverride PanelGraphical overrides for common fields (port/DNS/rules)
Clash Meta for AndroidConfig Add-onBasic field-overriding support on mobile

Writing a Declarative Merge

Take Clash Verge Rev's Merge feature as an example — the merge file is itself a YAML document. Fields written directly at the top level (like mixed-port) fully replace the matching field in the subscription. Fields prefixed with prepend- or append- insert content at the start or end of the subscription's corresponding list, which is commonly used to insert your own high-priority rules ahead of the subscription's rules:

mixed-port: 7893

prepend-rules:
  - DOMAIN-SUFFIX,corp.example.com,DIRECT
  - PROCESS-NAME,steam.exe,Select Node

append-proxies:
  - name: "Self-Hosted Backup"
    type: ss
    server: node9.example.com
    port: 8388
    cipher: aes-128-gcm
    password: "your-password"

The "prepend to the top of the rule table" behavior matters a lot here: since the first match wins, your private rules only get a chance to fire if they come before the subscription's rules. How dictionary-type fields (like dns) merge — full replacement vs. key-by-key merging — varies slightly between clients, so always test with a known piece of traffic after editing. The client comparison page has a side-by-side breakdown of where each client's override entry point lives and how it behaves; for the full setup flow on Windows, including service mode, see "Running Clash Verge Rev on Windows".

TipKeep override files as minimal as possible: only write the fields you actually need to change, rather than copying the whole subscription in and editing it there. The fewer fields you touch, the less likely you are to run into conflicts when the subscription's structure changes — and the easier it is to spot exactly where a problem is coming from.

9. Common Errors & a Config Troubleshooting Checklist

When a config fails to load, the core's log usually names the category of problem outright — read the log before you start editing, and you'll save yourself a lot of guesswork. Here's how to match common errors to their cause: anything starting with yaml: line N is a syntax error — check that line for bad indentation (a stray Tab is the usual suspect) or a missing space after a colon; proxy not found or proxy group ... not found means a group or rule references a name that doesn't exist, usually because a node got renamed without updating its references, or because a name has a stray space or emoji that doesn't quite match; unsupport proxy type means the config uses a protocol your current core doesn't recognize — either update the client or remove that node; bind: address already in use means the port is taken, covered in chapter 2; and if a rule set loads fine but never matches anything, the behavior mismatch from chapter 7 is the first thing to suspect.

A Seven-Step Checklist for Editing Configs Safely

  1. Back up first: copy your current working config file before touching anything. If an edit breaks something, you can revert instantly — it's the cheapest insurance you'll ever buy.
  2. Clear the syntax check: reload the config in your client right after saving, and don't move on to checking behavior until it loads successfully. If it fails to load, fix the syntax at the line number the log points to before stacking on more changes.
  3. Check name consistency: search the whole file for every node and group name you're referencing, and confirm proxies, proxy-groups, and rules all spell it identically — including spaces inside quotes.
  4. Verify rule order: confirm MATCH is the last rule, reject rules are placed early, and your private rules come before the subscription's rules (if using override, make sure it's actually prepending).
  5. Verify DNS behavior: with Fake-IP on, test local services like a LAN printer or screen casting — if they break, add the relevant domain to fake-ip-filter.
  6. Isolate with the three modes: if something "won't connect," switch to direct first to rule out your local network, then global to rule out the node, then back to rule to check your rules — change one variable at a time.
  7. Watch one full update cycle: confirm that after the subscription auto-updates, your overrides still apply and your port/DNS settings haven't reverted to defaults.

If you've gone through the checklist and still can't pin down the issue, go back to the getting started guide and check whether you missed a step in the basic setup. For a general list of things to check right after a fresh install, see "7 Settings to Check Right After Installing Clash". An outdated client version can also amplify all sorts of compatibility issues — updating to the current version from the download page before retesting is one of the highest-value steps in any troubleshooting flow.

Download Clash