Config File Structure and Reading Order

Clash's config.yaml is a YAML text file whose top-level fields the client reads in order at startup. The best way to understand it is to split the file into four sections from top to bottom: general settings, DNS configuration, proxy definitions, and proxy groups with rules.

YAML syntax rules are straightforward: use spaces for indentation (never tabs), keep indentation consistent within the same level, and separate keys from values with a colon followed by a space. Field order does not affect parsing, but proxies, proxy-groups, and rules reference each other: any node name used in a proxy group must be defined in proxies first, and any group name used in a rule must be defined in proxy-groups first. Writing the file in the order "general settings → DNS → proxies → proxy-groups → rules" matches how you read it and avoids errors from referencing undefined names.

Here is the skeleton of a minimal working config:

port: 7890
socks-port: 7891
allow-lan: false
mode: rule
log-level: info

dns:
  enable: true
  nameserver:
    - 223.5.5.5

proxies:
  - name: "Example Node"
    type: ss
    server: 203.0.113.10
    port: 443
    cipher: aes-256-gcm
    password: "example-password"

proxy-groups:
  - name: PROXY
    type: select
    proxies:
      - "Example Node"
      - DIRECT

rules:
  - DOMAIN-SUFFIX,github.com,PROXY
  - GEOIP,CN,DIRECT
  - MATCH,PROXY

This skeleton omits optional fields like ipv6 and external-controller, but it already covers the full flow: start the client, route traffic through the proxy, and split traffic by rules.

General Fields: Port, Mode, and Logging

The top-level general fields control the client's basic behavior. The table below lists the most commonly used ones:

Field Example Value Purpose
port 7890 HTTP proxy listening port
socks-port 7891 SOCKS5 proxy listening port
allow-lan false Allow connections from LAN devices
mode rule Running mode: rule / global / direct
log-level info Log level: silent / error / warning / info / debug
ipv6 false Enable IPv6 traffic
external-controller 127.0.0.1:9090 External controller API listen address

mode is the field people most often confuse because it has three possible values. In rule mode, traffic is matched against the rules section one by one and forwarded on the first hit — this is the mode you use every day. In global mode, all traffic goes through the first proxy group in proxy-groups, bypassing rule matching entirely. In direct mode, all traffic connects directly, effectively bypassing the proxy for everything — useful when troubleshooting node failures.

port and socks-port can be enabled at the same time, or you can enable only one of them. If port 7890 is already taken by another program on your machine, the startup log will show bind: address already in use — just change the port to an unused value like 7897.

external-controller provides a RESTful API. Clash Verge's dashboard, Yacd, and Metacubexd all read and modify the configuration through this address. By default it binds to 127.0.0.1, allowing access only from the local machine. If you set the secret field, you need to include the corresponding request header when calling the API.

For log-level, info is recommended for daily use; switch to debug temporarily when troubleshooting. debug prints rule-match details for every connection:

[TCP] dial Match(DomainSuffix): github.com → PROXY
[UDP] dial Match(GEOIP): 8.8.8.8 → DIRECT

This kind of log tells you exactly which rule picked up a connection, making it the most effective way to debug traffic splitting.

DNS Section: How nameserver and fallback split the work

The dns section decides which path domain resolution takes and is the second most important part of the configuration. The core fields are:

Field Example Value Purpose
enable true Take over the system DNS
listen 0.0.0.0:53 DNS server listen address
nameserver 223.5.5.5, 119.29.29.29 Default resolver servers
fallback 8.8.8.8, 1.1.1.1 Fallback resolver servers
fallback-filter geoip: true Conditions that trigger fallback
default-nameserver 223.5.5.5 Servers used to resolve proxy node domains

nameserver handles most domains. In mainland China, use public DNS servers such as 223.5.5.5 (Alibaba) and 119.29.29.29 (Tencent) — they respond quickly and are not polluted.

fallback is used for polluted domains: when an IP returned by nameserver is classified as a reserved address by geoip, the client re-resolves using the servers in fallback. In simple setups, setting fallback to 8.8.8.8 and 1.1.1.1 is enough.

There is a common pitfall here: if the nodes in proxies use domain names instead of IPs, the client also goes through the dns section when resolving node domains. If a node domain is polluted, every node will fail to connect. So default-nameserver must be set to a reliable DNS server in mainland China, and you should not hand node domain resolution over to the fallback flow. In TUN mode, enable under the dns section must be true; otherwise system traffic cannot resolve domains correctly once TUN is enabled.

proxies Section: How to Define Each Protocol

proxies is an array where each element defines a proxy node. All protocols share four base fields — name, type, server, and port — while protocol-specific fields vary.

An SS node has the fewest fields:

- name: "SS-Tokyo"
  type: ss
  server: 203.0.113.10
  port: 443
  cipher: aes-256-gcm
  password: "your-password"

Common cipher values include aes-256-gcm, chacha20-ietf-poly1305, and 2022-blake3-aes-256-gcm. The password must match the one provided by your subscription provider, or the handshake will fail immediately.

A VMess node adds uuid, alterId, and transport-layer fields:

- name: "VMess-Singapore"
  type: vmess
  server: 203.0.113.20
  port: 443
  uuid: "550e8400-e29b-41d4-a716-446655440000"
  alterId: 0
  cipher: auto
  network: ws
  ws-opts:
    path: "/path"
    headers:
      Host: "example.com"

alterId is usually 0 in newer server implementations. When network is ws, you must also configure path and Host under ws-opts; both must match your subscription provider's settings exactly, or the tunnel will fail to establish after the TLS handshake.

A Trojan node has a structure similar to VMess but without uuid:

- name: "Trojan-Los Angeles"
  type: trojan
  server: 203.0.113.30
  port: 443
  password: "your-password"
  sni: "example.com"
  skip-cert-verify: false

sni is used for the TLS SNI extension and must match the certificate domain. skip-cert-verify defaults to false and is not recommended to change to true unless the node's certificate is invalid and you accept the risk.

A Hysteria2 node additionally requires up and down bandwidth parameters:

- name: "Hysteria2-Hong Kong"
  type: hysteria2
  server: 203.0.113.40
  port: 443
  password: "your-password"
  up: "50 Mbps"
  down: "200 Mbps"
  sni: "example.com"

up/down declare the client's available bandwidth. Values that are too low will limit transfer speed; values that are too high may cause congestion.

proxy-groups: How Selection Logic Nests

proxy-groups defines policy groups. The proxies list inside a group can reference nodes or other groups. Four types are commonly used:

Type Behavior Use Case
select Manually select a node Daily driver, manual switching
url-test Tests latency on a schedule and automatically picks the lowest-latency node For automatic best-node selection
fallback Uses nodes in list order, switches to the next on failure When a fixed priority is needed
load-balance Distributes traffic evenly across multiple nodes Aggregating bandwidth across multiple nodes

The select type is the most straightforward:

- name: PROXY
  type: select
  proxies:
    - "SS-Tokyo"
    - "VMess-Singapore"
    - "Trojan-Los Angeles"
    - DIRECT
    - REJECT

url-test requires additional settings for the test URL and interval:

- name: Auto
  type: url-test
  url: "https://www.gstatic.com/generate_204"
  interval: 300
  tolerance: 50
  proxies:
    - "SS-Tokyo"
    - "VMess-Singapore"

interval is in seconds; 300 means a speed test every 5 minutes. tolerance means no switch when the latency difference is less than 50ms, preventing frequent flapping.

Proxy groups can be nested — this is an advanced pattern:

proxy-groups:
  - name: PROXY
    type: select
    proxies:
      - Auto
      - "SS-Tokyo"
      - DIRECT
  - name: Auto
    type: url-test
    proxies:
      - "SS-Tokyo"
      - "VMess-Singapore"

Here the first option in the PROXY group is the Auto group. When Auto is selected, actual traffic is decided automatically by url-test. There is no hard limit on nesting depth, but it is recommended to keep it to two levels or fewer; otherwise, figuring out which node is currently in use becomes difficult.

rules Section: Match Order Determines Traffic Direction

rules is the last section of the config and the core of traffic splitting. Clash matches rules one by one in order and stops at the first hit — it does not keep going. This makes rule order extremely important.

Common rule types:

Rule Prefix Matches Example
DOMAIN Full domain DOMAIN,www.google.com,PROXY
DOMAIN-SUFFIX Domain suffix DOMAIN-SUFFIX,google.com,PROXY
DOMAIN-KEYWORD Domain keyword DOMAIN-KEYWORD,github,PROXY
IP-CIDR IPv4 CIDR IP-CIDR,192.168.0.0/16,DIRECT
GEOIP Country or region GEOIP,CN,DIRECT
PROCESS-NAME Process name PROCESS-NAME,wechat.exe,DIRECT
MATCH Fallback MATCH,PROXY

A production-ready rules example:

rules:
  - DOMAIN-SUFFIX,local,DIRECT
  - IP-CIDR,127.0.0.0/8,DIRECT
  - IP-CIDR,192.168.0.0/16,DIRECT
  - IP-CIDR,10.0.0.0/8,DIRECT
  - DOMAIN-SUFFIX,cn,DIRECT
  - GEOIP,CN,DIRECT
  - DOMAIN-SUFFIX,google.com,PROXY
  - DOMAIN-SUFFIX,youtube.com,PROXY
  - DOMAIN-KEYWORD,github,PROXY
  - MATCH,PROXY

Notice the order above: LAN and mainland China traffic is picked up by DIRECT first, then foreign domains are matched to PROXY, and finally MATCH catches everything else. If you put DOMAIN-SUFFIX,google.com,PROXY before GEOIP,CN,DIRECT, and google.com resolves to a mainland China IP (for example, because a CDN scheduled it to a node in mainland China), it would incorrectly connect directly.

The rule target (the last field) must be a group name defined in proxy-groups, or one of the built-in targets DIRECT and REJECT. Referencing a group name that does not exist will cause config validation to fail immediately.

Rule order is priority. Clash matches rules one by one starting from the first line of rules and stops at the first hit. If you put broad rules (such as GEOIP,CN,DIRECT) before specific rules (such as DOMAIN-SUFFIX,google.com,PROXY), the latter will never get a chance to match.

Validating Your Config and Common Errors

After writing config.yaml, validate the syntax from the command line before starting the client — this saves a lot of debugging time. The mihomo core validation command:

./mihomo -t -f config.yaml

Output showing configuration file ... test is successful means it passed. Clash Verge's "Settings" → "Parameters" also provides a config check entry, which essentially calls the same validation logic.

Common errors, ordered by how often they occur:

  1. Indentation uses tabs. YAML only accepts spaces — enable "Convert tabs to spaces" in your editor to avoid this.
  2. Missing space after the colon. port:7890 is parsed as a string key instead of the port field.
  3. Special characters in passwords are not quoted. If a password contains characters like #, :, or *, it must be wrapped in double quotes; otherwise YAML treats them as comments or structural symbols.
  4. Referencing an undefined node name or group name. Check that the name values in proxies exactly match the proxies lists in proxy-groups.
  5. Defining duplicate nodes with the same name. The later definition overrides the earlier one, which often creates the illusion that "you changed the config but nothing changed."

Compare the validation command output against the checklist above, and most config issues can be located within 5 minutes.