config reference

Clash Configuration File Reference

This page is a field-level reference for config.yaml, organized in the order "structure overview → general fields → DNS → nodes → proxy groups → rules → external providers → override merging → validation/troubleshooting." It has a clear division of labor with the Quick Start page: that page walks you through importing a subscription and getting proxying working for the first time, while this page is for looking up specific fields whenever you need to modify, extend, or debug a configuration. All examples follow mihomo kernel syntax (i.e. the Clash Meta kernel), which is the runtime foundation of the clients in the Download Center — Clash Plus, Clash Verge Rev, FlClash and others — so field behavior is identical across them.

KERNEL: mihomo FORMAT: YAML UPDATED: 2026-07-18

1. YAML Structure Overview

Every behavior of Clash is driven by a single YAML configuration file. Every toggle on the client's interface, every proxy group, every routing rule ultimately maps to some field in this file. Understanding its overall structure is the prerequisite for everything else you'll do to it: knowing which section a field belongs to tells you what a change will affect, and whether it will get wiped out by the next subscription update.

A complete configuration is made up, at the top level, of several fixed-name sections; the kernel identifies them by name, so order doesn't affect parsing. The common sections are:

  • General fields: scalar settings scattered at the top level, such as mixed-port, mode, and log-level, controlling ports, proxy mode, and runtime parameters;
  • dns: domain resolution behavior, including whether the built-in DNS is enabled, Fake-IP mode, and the list of upstream servers;
  • proxies: an array of proxy nodes, each entry describing one outbound server's protocol, address, and credentials;
  • proxy-groups: an array of proxy groups, organizing nodes into selectable groups that can also auto-test latency;
  • rules: an array of routing rules that decide which proxy group or direct connection each connection uses;
  • proxy-providers / rule-providers: importing nodes and rule sets from an external URL or local file, making maintenance easier to split up;
  • tun: virtual network adapter mode, used when taking over all system traffic.

A minimal working configuration needs only three parts: one inbound port, at least one node (or just DIRECT), and one catch-all rule. You can save the skeleton below directly as config.yaml to verify it:

mixed-port: 7897
mode: rule
log-level: info

proxies: []

proxy-groups: []

rules:
  - MATCH,DIRECT

YAML has a handful of strict conventions, and most parsing failures come down to one of them. First, hierarchy is expressed entirely through indentation, and the indentation width at the same level must be consistent — the convention is two spaces. Second, a colon must be followed by a space; mode:rule is invalid. Third, field names are case-sensitive — Mode will not be recognized as mode. Fourth, strings generally don't need quotes, but when they contain special characters like colons, hashes, or asterisks they must be quoted, e.g. a password like "p@ss:word#1".

Never use tab indentation

The YAML spec does not accept tab-character indentation; the kernel will reject the file outright with found a tab character that violates indentation. Before editing a config in Notepad, vim, or any other editor, make sure the editor maps the Tab key to spaces — and check that snippets pasted from a web page haven't smuggled in tab characters at the start of a line.

For where the config file is stored and which sections get wholesale-replaced when a subscription updates, see the site article "Understanding the Clash Profile Structure"; Chapter 8 of this page also covers how to keep local edits alive across updates.

2. General Fields: Ports, Mode, and Runtime Control

General fields sit directly at the top level of the config and control how the kernel runs. There aren't many of them, but almost every troubleshooting session starts here — port conflicts, the wrong mode, LAN devices that can't connect: the root cause is usually in this section.

2.1 Inbound ports

The kernel can open multiple kinds of inbound listeners at once. port is a plain HTTP proxy port, socks-port is a plain SOCKS5 port, and mixed-port recognizes both HTTP and SOCKS5 requests on the same port — the default choice for most clients today, since the system proxy and third-party software can all point at one single port, which keeps configuration simple. All three can coexist, but listening port numbers can't repeat, and can't clash with ports already used by other programs on the system; a bind: address already in use error at startup means the port is taken, so switch to an unused one.

2.2 LAN access

allow-lan decides whether the inbound port accepts connections from outside the local machine. Setting it to true lets a phone or TV box on the same LAN point its proxy settings at this machine's local IP and share the same outbound routes and rules; combined with bind-address, you can restrict listening to a specific network interface. Before enabling it, be mindful of the network you're on: opening LAN access on a work or public Wi-Fi network means any device on the same subnet can use this proxy port.

2.3 Proxy mode (mode)

mode accepts three values: rule (match traffic against the rules section entry by entry), global (send all traffic to a single global outbound), and direct (send all traffic direct). Day-to-day, you should stay on rule — the other two are diagnostic tools, not standing options. For when to switch temporarily and how to verify the result, see the site article "Choosing Between Clash's Three Proxy Modes" for the full procedure.

2.4 Quick reference for common general fields

FieldType / ValuesDescription
mixed-port1-65535Mixed HTTP + SOCKS5 inbound port, recommended as the sole inbound
allow-lantrue / falseWhether LAN devices can reach this machine's proxy port
bind-addressIP / "*"Listening address, works with allow-lan to restrict interfaces
moderule / global / directProxy mode; keep it on rule day-to-day
log-levelsilent / error / warning / info / debugLog verbosity; bump to debug temporarily when troubleshooting
ipv6true / falseWhether to handle IPv6 traffic; disable if your network doesn't support it to reduce resolution noise
external-controllerIP:portRESTful control API address, which client panels rely on to read/write kernel state
secretstringAccess token for the control API; make sure to set one when exposing it to a LAN

external-controller deserves a closer look: it exposes an HTTP API, and the client's graphical interface uses exactly this API to switch nodes and read latency and traffic data. It's bound to 127.0.0.1:9090 by default, open only to the local machine; if you change it to 0.0.0.0:9090 so a LAN panel can reach it, you must also set secret, or any device on the same subnet can control the kernel directly.

2.5 TUN section at a glance

The system proxy only affects apps that respect proxy settings — command-line tools, games, and some client software bypass it entirely. The tun section takes over all traffic at the network layer by creating a virtual network adapter, solving the "I set a proxy but this one app just won't use it" problem:

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

stack selects the protocol stack implementation (system / gvisor / mixed) — try switching between them if you hit compatibility issues; auto-route automatically writes system routing table entries; dns-hijack intercepts plaintext DNS queries sent to port 53 and redirects them to the built-in DNS, working together with the next chapter's settings to prevent resolution bypass. Enabling TUN requires administrator or root privileges, and each client will guide you through installing the corresponding system service.

3. DNS Section: Resolution Behavior and Fake-IP

DNS is the most commonly overlooked piece of a proxy setup: if domain resolution still goes through your local ISP's plaintext port 53, then even though your traffic itself is proxied, which domains you visited is still exposed on the local network path, and some domains may resolve to poisoned addresses that break the connection outright. The dns section is what lets the kernel take over resolution and decide "who resolves it, how, and how the result gets used."

3.1 Basic toggles and listening

dns:
  enable: true
  listen: 0.0.0.0:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16

enable: true turns on the built-in DNS module; listen lets it also act as a regular DNS server for the outside world, mainly paired with TUN's dns-hijack or router setups. enhanced-mode is the core choice in this section, determining how resolution results are presented.

3.2 Fake-IP vs. Redir-Host

In fake-ip mode, the kernel doesn't wait for real resolution to finish; it immediately hands the app a virtual address allocated from the reserved fake-ip-range block (default 198.18.0.1/16), while remembering which domain that virtual address maps to. When the app connects using that virtual address, the kernel matches rules by domain rather than IP and forwards accordingly. The upside is skipping one resolution round trip, noticeably lowering first-packet latency, and rule matching is always domain-based, which is more accurate. redir-host returns the real resolution result, behaving more like traditional DNS — better compatibility, but slightly worse in speed and matching precision. For the mechanics behind the two modes, and cases like LAN services and game multiplayer that need to avoid Fake-IP, see the site article "How Clash's Fake-IP Mode Actually Works", which breaks it down in detail.

When using Fake-IP, certain lookups that must get a real IP need to be excluded via fake-ip-filter — typical examples are LAN hostnames, system connectivity-check domains, and NTP services:

  fake-ip-filter:
    - "*.lan"
    - "+.local"
    - "+.msftconnecttest.com"
    - "+.pool.ntp.org"

Here * matches a single subdomain level, while + matches any number of subdomain levels and the domain itself.

3.3 The three-tier upstream server structure

  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query
  fallback:
    - https://1.1.1.1/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN

These three groups of servers serve different roles and shouldn't be conflated. default-nameserver must only contain plain IPs, and exists purely to resolve the domain names of the two encrypted DNS groups below it — solving the chicken-and-egg problem. nameserver is the primary resolution group, and it's recommended to use encrypted protocols like DoH (https:// prefix) or DoT (tls:// prefix). fallback is the backup group, working together with fallback-filter: when the primary group's result matches the filter condition (e.g. anything outside geoip-code: CN), the kernel switches to the backup group's answer instead, countering DNS poisoning. If you don't need this dual-lookup mechanism, you can keep just the nameserver group.

Checking for DNS leaks

In system-proxy mode, an app's DNS queries don't necessarily go through the kernel — resolution is only fully taken over in TUN mode combined with dns-hijack, or when the app itself connects through the proxy port. If a leak-test tool shows your ISP's DNS as the resolver, first check whether TUN is enabled and whether enable under the dns section is set to true. For more diagnostic methods, see the troubleshooting category on the FAQ page.

4. Proxy Node Fields (proxies)

proxies is an array where each entry fully describes one outbound node. In a subscription-based config, this section is generated by the provider and usually doesn't need to be hand-edited — but when self-hosting nodes, adding your own private outbound to a subscription, or diagnosing why a particular node won't connect, you need to be able to read what each field means.

4.1 Fields shared by every protocol

Regardless of protocol, four fields are always required: name (the node's name, referenced by proxy groups — must be unique within a config), type (protocol type), server (the server's domain or IP), and port (the server port). In addition, udp: true declares that the node supports UDP forwarding, which is needed by voice calls, games, and other UDP-dependent apps.

4.2 Three common protocol examples

proxies:
  - name: "HK-01"
    type: ss
    server: hk01.example.com
    port: 8388
    cipher: aes-256-gcm
    password: "your-password"
    udp: true

  - name: "JP-01"
    type: vmess
    server: jp01.example.com
    port: 443
    uuid: 0f7b7c4e-3a52-4e70-9d2b-1c8a5f6e0d43
    alterId: 0
    cipher: auto
    tls: true
    network: ws
    ws-opts:
      path: /ws
      headers:
        Host: jp01.example.com

  - name: "US-01"
    type: trojan
    server: us01.example.com
    port: 443
    password: "your-password"
    sni: us01.example.com
    udp: true

For Shadowsocks (ss), the key fields are the cipher encryption method and password, which must match exactly on both ends. VMess uses uuid as its identity credential, and alterId is fixed at 0 under the current protocol; network declares the transport layer (ws, grpc, http, etc.), and whichever transport you pick determines which *-opts sub-section you need — the example's ws-opts specifies the WebSocket path and Host header. Trojan runs on top of TLS by design, and sni specifies the server name declared during the handshake; a mismatch with the server certificate will cause the connection to fail outright.

Beyond these three, the mihomo kernel also supports protocols like vless, hysteria2, tuic, and wireguard, whose fields follow the same pattern: the four common fields plus protocol-specific fields. When you get a node using a protocol you haven't used before, first confirm the type spelling matches the kernel's supported list, then fill in the credential fields it requires one by one.

Use skip-cert-verify sparingly

TLS-based nodes (vmess+tls, trojan, vless, etc.) support skip-cert-verify: true to skip certificate validation. This should only be a temporary measure while diagnosing a certificate issue — leaving it on long-term means giving up on verifying the server's identity, letting a man-in-the-middle impersonate the node server. In a production config, keep certificate validation on by default unless your provider explicitly requires otherwise.

5. Proxy Group Fields (proxy-groups)

If proxies are the raw materials, proxy-groups is the layer that organizes them into "decidable units." The outbound target in the rules section almost always points at a proxy group rather than a single node — that way, switching nodes only requires switching within the group, and the rules never need to change. The group-selection list in the client's main interface is simply a visualization of this section.

5.1 Four group types

TypeBehaviorTypical use
selectManual selection; remembers your last choiceA top-level master switch group, or business-purpose groups
url-testPeriodically tests latency and auto-picks the fastest nodeAn "auto" group for when you don't want to pick nodes by hand
fallbackTakes the first available node in list order, auto-advancing when one failsA primary/backup structure: prefer a fixed main node, fall back on failure
load-balanceSpreads connections across multiple nodes by policySharing concurrent load across multiple nodes to reduce single-point pressure

5.2 A full example with parameter notes

proxy-groups:
  - name: "Proxy"
    type: select
    proxies:
      - Auto
      - HK-01
      - JP-01
      - US-01
      - DIRECT

  - name: "Auto"
    type: url-test
    url: http://www.gstatic.com/generate_204
    interval: 300
    tolerance: 50
    lazy: true
    proxies:
      - HK-01
      - JP-01
      - US-01

The three parameters on auto-type groups directly affect the experience. url is the test target — convention is to use a lightweight address that returns a 204 status, testing the full round trip of "reaching this address through this node." interval is the test interval in seconds; too short and it generates a lot of probe traffic. tolerance is the switching tolerance in milliseconds — a new fastest node must beat the current one by more than this margin before the group switches, avoiding constant flip-flopping between two nodes with close latencies. lazy: true pauses testing for a group that isn't currently in use, cutting background overhead.

Groups can reference other groups: in the example, "Proxy" lists "Auto" as its first option, forming a two-tier "manual on top, automatic underneath" structure. The regional groups commonly seen in subscriptions — "Hong Kong," "Japan," and so on — funneling into one master group is the same kind of nesting. Two reserved names can appear directly in any group: DIRECT means a direct connection, and REJECT means refuse the connection (commonly used as the outbound for ad-blocking rules). Note that groups and nodes share the same namespace — a group name can't duplicate a node name, and groups can't form a cycle: group A containing group B which in turn contains group A will fail to load.

6. Rule Syntax (rules)

The rules section decides where every connection goes, and it's the part of the whole config most worth maintaining by hand. Each rule is a single line of comma-separated text in the basic form "type,match value,outbound," where the outbound is a proxy group name, a node name, or DIRECT / REJECT.

6.1 Match order: top to bottom, first match wins

For every new connection, the kernel tries rules starting from the first one and stops at the first match, using that rule's outbound — the rules after it never get a chance. This single mechanism explains every principle of good rule ordering: specific rules go first, broad rules go later, and a catch-all rule goes last. If a GEOIP,CN,DIRECT rule is placed before a proxy rule targeting a specific domain, and that domain happens to resolve to an IP inside mainland China, the domain rule after it will never fire — the vast majority of "I wrote this rule but it's not working" issues come down to ordering.

6.2 Common rule types

TypeMatches againstExample
DOMAINExact domain matchDOMAIN,dl.example.com,DIRECT
DOMAIN-SUFFIXThe domain itself and any of its subdomainsDOMAIN-SUFFIX,openai.com,Proxy
DOMAIN-KEYWORDDomain contains a keywordDOMAIN-KEYWORD,github,Proxy
IP-CIDRTarget IPv4 falls inside a subnetIP-CIDR,192.168.0.0/16,DIRECT,no-resolve
IP-CIDR6Target IPv6 falls inside a subnetIP-CIDR6,fd00::/8,DIRECT,no-resolve
GEOIPTarget IP's geolocation database entryGEOIP,CN,DIRECT
PROCESS-NAMEName of the process initiating the connection (desktop)PROCESS-NAME,steam.exe,DIRECT
DST-PORTDestination portDST-PORT,22,DIRECT
RULE-SETReferences a rule-providers rule setRULE-SET,telegram,Proxy
MATCHUnconditional match; must be the last ruleMATCH,Proxy

DOMAIN-SUFFIX,example.com matches both example.com and a.b.example.com, making it the most commonly used type for covering an entire site; DOMAIN-KEYWORD has the broadest reach and is easy to misfire on, so only use it when you're sure the keyword is distinctive enough. The no-resolve parameter at the end of IP-type rules means "if the current connection's target is a domain rather than an IP, skip this rule rather than triggering a resolution just to check it" — adding it to LAN subnet rules prevents every domain-based connection from being resolved upfront just to slow down matching.

6.3 A ready-to-use ordering

rules:
  - PROCESS-NAME,steam.exe,DIRECT
  - DOMAIN,dl.example.com,DIRECT
  - DOMAIN-SUFFIX,openai.com,Proxy
  - DOMAIN-KEYWORD,github,Proxy
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - GEOIP,CN,DIRECT
  - MATCH,Proxy

This layout reflects the recommended hierarchy: process and exact-domain rules first, business domain rules next, LAN subnet and geolocation-based direct rules further down, and MATCH closing things out as the catch-all. Any rule after MATCH is dead code — the kernel won't error, but it will never run, so when auditing a config you can treat it as an "end of rules" marker. For how to verify which rule a custom entry actually matches, see the logging method in Chapter 9.

7. External Providers: proxy-providers and rule-providers

When nodes come from multiple subscriptions and rule entries number in the thousands, cramming everything into one YAML file quickly becomes unmanageable. The provider mechanism lets you split node lists and rule sets into standalone files that the kernel pulls updates for on a schedule, while the main config only keeps a reference.

7.1 proxy-providers: node sources and health checks

proxy-providers:
  main-sub:
    type: http
    url: "https://example.com/subscribe/token"
    path: ./providers/main-sub.yaml
    interval: 86400
    health-check:
      enable: true
      url: http://www.gstatic.com/generate_204
      interval: 600

proxy-groups:
  - name: "Subscription"
    type: select
    use:
      - main-sub

type: http means fetching from a remote address; path is the local cache path (if fetching fails, the cached copy is used, so the setup can still start offline); interval is the auto-update period in seconds. health-check has the kernel periodically test the availability of every node from that source, and failed nodes are skipped in auto-type groups. Proxy groups reference a provider name via the use field, which can coexist with the proxies field — a group can contain both hand-written nodes and an entire subscription source.

7.2 rule-providers: the three behavior modes

rule-providers:
  telegram-ip:
    type: http
    behavior: ipcidr
    format: yaml
    url: "https://example.com/rules/telegram.yaml"
    path: ./rules/telegram-ip.yaml
    interval: 86400

rules:
  - RULE-SET,telegram-ip,Proxy

behavior declares the content shape of the rule set file, and the three values can't be mixed: domain means the file is entirely domain entries, ipcidr means entirely subnet entries — for both, the kernel builds an efficient index, well suited to lists with tens of thousands of entries; classical means the file contains full rule lines with type prefixes, more flexible but with a higher matching cost. format supports yaml and text, and must match the file's actual format. The main config references it with RULE-SET,rule-set-name,outbound, and this line's position within the rules section still follows the ordering principle from Chapter 6.

Choosing an update interval

interval doesn't need to be very short: once a day (86400) is usually enough for node subscriptions, and rule sets change even more slowly, so once every few days is fine too. Too short an interval wastes bandwidth and, when the source server is unstable, triggers frequent fetch-failure log entries that muddy your troubleshooting.

8. Overrides and Merging: Surviving Subscription Updates

Editing a subscription-generated config file directly has a fundamental problem: a subscription update is a wholesale replacement, so any nodes you added or rules you edited by hand will all be wiped out the next time it updates. There's only one solution — keep "content provided by the subscription" and "locally customized content" stored separately, and have the client merge them at load time. Every client offers this mechanism, under different names but with the same underlying idea.

8.1 Client-side override mechanisms

Clash Plus, the top pick in the Download Center, provides a config override entry point that lets you append rules and nodes without touching the subscription's original content. Clash Verge Rev offers two kinds of extended configuration — "Merge" and "Script": Merge describes additions and replacements declaratively in YAML, while Script uses a JavaScript function to rewrite the config object at load time, which can handle conditional logic. FlClash also supports config overrides. No matter which client you use, the principle is the same: the subscription file itself always stays read-only, and every customization lives in the override layer.

8.2 A Merge-style override example

prepend-rules:
  - DOMAIN-SUFFIX,internal.example.com,DIRECT
  - PROCESS-NAME,steam.exe,DIRECT

append-rules:
  - DOMAIN-KEYWORD,tracker,REJECT

append-proxies:
  - name: "Self-Hosted-HK"
    type: ss
    server: my.example.com
    port: 8388
    cipher: aes-256-gcm
    password: "your-password"

prepend-* inserts entries at the very front of the corresponding section, and append-* adds them to the very end. Which direction to choose depends on the rule matching order: custom rules you want matched first should use prepend-rules; catch-all-style blocking rules should use append-rules — but be careful, since it lands after the subscription's existing MATCH rule if there is one; if the subscription already ends with a MATCH, an appended rule is effectively unreachable, and in that case you should use prepend instead, or replace the entire rules section outright. For scalar or mapping fields like mixed-port and dns, writing the same field name in the override layer replaces it entirely.

8.3 Manual maintenance scenarios

On a Linux server or any other environment running the mihomo kernel directly without a graphical client, there's no ready-made merge layer. The recommended approach is to download the subscription as a baseline file, then stitch your custom sections into a final config via script or by hand, replacing only the baseline portion when the subscription updates. For directory organization and a systemd-based always-on setup, see the site article "Two Ways to Deploy Clash on Linux".

Back up before you edit

No matter which method you use to make a change, copy the currently working config file somewhere outside the config directory before you touch anything. If your merge logic breaks, rolling back to the backup is by far the fastest fix — much quicker than hunting through logs line by line. For the specifics of switching between multiple configs and backing them up, see the Profile Management Guide.

9. Validation and Troubleshooting

Don't just reload a config after editing it and hope for the best — verify the syntax first, then observe the behavior. Doing so cuts the time needed to pin down a problem dramatically. This chapter lays out a fixed verification sequence.

9.1 Before loading: syntax validation

The mihomo kernel ships with a config test flag that parses the file without starting the service, giving you a result within seconds:

mihomo -t -f config.yaml

Output of configuration file test is successful means the syntax passed; otherwise it prints the offending field path and line number. Desktop clients run the same validation when importing or saving a config and pop up error details, with wording matching the kernel's — you can look it up directly in the table below.

9.2 Common error reference

Error keywordCauseFix
found a tab characterA tab character got mixed into the start of a lineReplace every tab with spaces; standardize on two-space indentation
did not find expected keyIndentation level is off, so a field ended up under the wrong parentCheck that the indentation width of the offending line matches its context
proxy not found / group not foundA rule or group references a name that doesn't existCheck the spelling and full-width/half-width spaces, and confirm the referenced target actually exists
bind: address already in useThe inbound or control port is taken by another programSwitch ports, or find and kill the process using it
duplicate proxy nameA node or group name is duplicatedRename one of them — remember groups and nodes share a namespace
unsupported proxy typeThe type is misspelled, or the kernel doesn't support that protocolCheck the protocol name spelling and confirm you're running the mihomo kernel

9.3 After loading: observing actual behavior

Passing syntax validation doesn't guarantee routing behaves as expected. Temporarily set log-level to debug and reload — the client's log panel will print a line for every connection, in a format like example.com:443 --> Proxy (match DOMAIN-SUFFIX/example.com), spelling out exactly which rule each connection matched and which outbound it took. This is the most reliable way to verify a custom rule, far more efficient than refreshing a web page and guessing. Once you've confirmed it's correct, remember to switch the log level back to info — debug-level logging generates a lot of output.

To confirm the kernel is alive from the command line, you can query the control API directly:

curl -s http://127.0.0.1:9090/version -H "Authorization: Bearer your-secret"

A normal JSON response means the kernel is running and the control API is reachable; no response means the kernel hasn't started, or the external-controller address doesn't match what you expect. If the client crashes on launch before you can even see a log, work through "Troubleshooting Clash Client Launch Crashes", which lists log locations and a verification sequence for each platform.

9.4 What's next

If you've read this far without a working baseline setup yet, go back to Quick Start first and follow the main flow to get your first connection working, then come back here for whichever chapter matches your specific need. Get the client itself from the Download Center based on your platform — Clash Plus is the top pick across every platform. The most frequent questions that come up during day-to-day use — launching at startup, expired subscriptions, node timeouts, and the like — are gathered on the FAQ page, which complements this one.

Download Clash