Clash Configuration File Explained: Read YAML from port to rules

A practical walkthrough of a complete Clash config, covering common fields, dns, proxy definitions, proxy-groups, and rules—with examples and pitfalls for each section.

Start with YAML’s hierarchy and parsing rules

Clash configuration files typically use YAML. They are not a series of unrelated switches, but a hierarchical configuration tree: top-level fields control core behavior, indented fields belong to the object above them, and entries beginning with a hyphen are list items. When reading a config, check indentation first, then interpret each field. Looking only at field names without their level can easily place a valid parameter in the wrong location.

Indentation, colons, and lists

  • Use spaces consistently for indentation. Two spaces per level is common; do not mix in tabs.
  • Put a space after the colon in a key, such as mode: rule.
  • Fields such as dns: and profile: have nested items below them, and those items must be indented further.
  • proxies:, proxy-groups:, and rules: usually contain lists, with each item beginning with -.
  • Names containing special characters such as colons, hash signs, or braces should be wrapped in single or double quotes.
mode: rule
log-level: info

profile:
  store-selected: true
  store-fake-ip: true

proxy-groups:
  - name: 'Proxy Selection'
    type: select
    proxies:
      - 'Auto Select'
      - DIRECT

In the example above, store-selected belongs to profile, while name, type, and proxies together form a proxy-group object. If the indentation of type and name does not align, YAML may still parse but produce a completely different data structure.

Common fields: ports, LAN access, and operating mode

The beginning of a config commonly defines listening ports, operating mode, log level, and the controller port. These fields determine how the application receives system traffic and how a GUI client communicates with the Clash Meta (mihomo) core.

port: 7890
socks-port: 7891
mixed-port: 7893
redir-port: 7892
tproxy-port: 7895

allow-lan: false
bind-address: '*'
mode: rule
log-level: info
ipv6: false

external-controller: 127.0.0.1:9090
secret: 'change-this-controller-secret'

What traffic does each port handle?

port
HTTP proxy listening port. The address in examples is usually 127.0.0.1:7890.
socks-port
SOCKS5 proxy port. Command-line tools or applications that support SOCKS5 can connect to 127.0.0.1:7891.
mixed-port
Accepts HTTP and SOCKS5 requests on the same port. Keep this option when the client only needs to expose one local proxy endpoint.
redir-port
Used for Linux redirection setups, typically together with iptables or compatible traffic-forwarding rules.
tproxy-port
Used for Linux TPROXY transparent proxying, handling forwarded traffic that needs to preserve its destination address.

You do not need to enable every port. For desktop clients using the system proxy, a common setup enables only mixed-port: 7890, or enables separate HTTP and SOCKS ports. If the log shows address already in use, check whether another proxy, an old core process, or a development service is already using the port before changing the config or stopping the conflicting process.

mode, allow-lan, and the controller interface

  • mode: rule matches rules from top to bottom and is the most common mode for everyday traffic splitting.
  • mode: global sends connections to the global proxy group instead of applying ordinary rules one by one.
  • mode: direct connects directly, which is useful for checking whether a problem comes from the proxy chain.
  • allow-lan: true lets devices on the local network connect to the listening port. Also check the system firewall, bind address, and trusted network boundary when enabling it.
  • external-controller is the REST API controller interface. For local-only use, bind it to 127.0.0.1; for a remote dashboard, set a valid secret and restrict network access.

bind-address: '*' listens on available addresses, but whether it is actually exposed to the LAN is controlled by allow-lan and the firewall. Do not treat the bind address, LAN access, and controller interface as the same setting: they manage the proxy entry point, LAN permission, and core management API respectively.

DNS: resolution paths and Fake-IP

DNS settings determine how domains are resolved and can affect whether domain rules continue matching when a connection is made. Common enhanced modes in Clash Meta (mihomo) include fake-ip and redir-host. The former returns a mapped address from a reserved range while the core maintains the domain-to-connection mapping; the latter is closer to returning the real resolution result.

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter:
    - '*.lan'
    - '*.local'
    - 'time.*.com'
    - 'time.*.gov'
  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'
    - 'https://dns.google/dns-query'
  fallback-filter:
    geoip: true
    geoip-code: CN

The roles of the three nameserver types

  • default-nameserver usually contains directly reachable IP addresses used to resolve the hostnames of DoH or DoT servers themselves, avoiding a circular dependency during startup.
  • nameserver is the primary resolver. It can use ordinary UDP DNS or encrypted resolvers such as DoH and DoT.
  • fallback provides backup resolvers. Whether its results are used depends on conditions such as fallback-filter.

listen: 127.0.0.1:1053 makes the DNS listener accessible only from the local machine. If the client already takes over system DNS automatically, you usually do not need to point the operating system’s DNS to this port manually. In TUN mode, the core may also receive port 53 requests through DNS hijacking; the exact behavior depends on the TUN config generated by the client.

What belongs in fake-ip-filter?

LAN domains, device-discovery domains, some time-synchronization domains, and application domains that require real addresses can be added to fake-ip-filter. Avoid adding broad wildcards indiscriminately: many domains would bypass Fake-IP mapping, changing domain-rule matching and first-connection latency.

proxies: defining individual nodes

proxies is a static list of nodes. Each node needs at least a name, protocol type, server address, and port; protocol-specific authentication and transport fields come next. Node fields must match the server’s actual setup. Sharing a protocol name does not mean the port, encryption, TLS hostname, or WebSocket path can be interchanged.

proxies:
  - name: 'Example-Trojan'
    type: trojan
    server: edge.example.com
    port: 443
    password: 'example-password'
    udp: true
    sni: edge.example.com
    skip-cert-verify: false

  - name: 'Example-VMess'
    type: vmess
    server: vm.example.com
    port: 443
    uuid: 00000000-0000-4000-8000-000000000001
    alterId: 0
    cipher: auto
    udp: true
    tls: true
    servername: vm.example.com
    network: ws
    ws-opts:
      path: /connect
      headers:
        Host: vm.example.com

Node names are reference keys

name is more than display text: proxy groups reference nodes using the exact same string. If a node is named Example-Trojan, writing Example Trojan in a proxy group creates a reference to a node that does not exist. When renaming a node, check every proxy-groups, rule target, and chained-proxy setting.

TLS and transport fields must match

  • server is the server address used to establish the connection.
  • sni or servername supplies the server name for the TLS handshake and should match the value provided by the node operator.
  • skip-cert-verify: false enables normal server-certificate verification.
  • network: ws selects WebSocket transport, with its parameters under ws-opts.
  • udp: true allows the node to handle UDP. Actual connectivity still depends on the protocol, server, and network environment.

When importing a subscription, nodes are often not written directly under proxies. The client may generate them after conversion or load them through proxy-providers. Both approaches can coexist, but duplicate node names make proxy-group references and troubleshooting harder.

proxy-providers and proxy-groups: from nodes to policies

proxy-providers loads a set of nodes from a local file or remote URL, while proxy-groups organizes them into selectable, latency-tested, or failover policies. Rules usually point to a proxy group rather than a specific node.

proxy-providers:
  provider-main:
    type: http
    url: 'https://subscription.example.com/clash'
    path: ./providers/provider-main.yaml
    interval: 3600
    health-check:
      enable: true
      url: 'https://www.gstatic.com/generate_204'
      interval: 600

proxy-groups:
  - name: 'Proxy Selection'
    type: select
    proxies:
      - 'Auto Select'
      - DIRECT
    use:
      - provider-main

  - name: 'Auto Select'
    type: url-test
    use:
      - provider-main
    url: 'https://www.gstatic.com/generate_204'
    interval: 300
    tolerance: 80

  - name: 'Failover'
    type: fallback
    use:
      - provider-main
    url: 'https://www.gstatic.com/generate_204'
    interval: 300

Common proxy-group types

  • select: manually choose a node or another proxy group. This is suitable for the destination referenced by rules.
  • url-test: periodically requests a test URL and selects the lowest-latency candidate. The example checks every 300 seconds; tolerance: 80 helps prevent frequent switching when latency is similar.
  • fallback: selects candidates by availability and switches to the next usable node when the current connection path fails.
  • load-balance: distributes connections across multiple nodes according to a policy. It does not directly combine the bandwidth of a single download.

proxies explicitly lists node or proxy-group names, while use references providers. Proxy groups can be nested—for example, “Proxy Selection” can include “Auto Select,” which then draws nodes from a provider. When checking a config, follow references level by level and verify that every name exists; avoid creating a group that references itself.

rules: the ordered traffic-splitting table

rules is one of the most important lists near the end of a config. Clash matches from top to bottom and normally stops after the first match. Put specific domain, process, or subnet rules first, followed by broader GeoIP, GeoSite, and catch-all rules.

rules:
  - DOMAIN-SUFFIX,example.org,Proxy Selection
  - DOMAIN,api.example.net,Auto Select
  - DOMAIN-KEYWORD,stream,Proxy Selection
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - GEOSITE,CN,DIRECT
  - GEOIP,CN,DIRECT,no-resolve
  - MATCH,Proxy Selection

Rules consist of a matcher, value, and target

In DOMAIN-SUFFIX,example.org,Proxy Selection, the first part is the rule type, the second is the value to match, and the third is the policy used after a match. The policy name must exactly match a name in proxy-groups; built-in targets such as DIRECT and REJECT are also valid.

  • DOMAIN exactly matches one fully qualified domain name.
  • DOMAIN-SUFFIX matches a specified domain and its subdomains, making it useful for site-wide traffic splitting.
  • DOMAIN-KEYWORD matches keywords in domain names. Because its scope is broad, avoid overly short keywords.
  • IP-CIDR and IP-CIDR6 match IPv4 and IPv6 address ranges respectively.
  • GEOIP uses a geographic IP database to determine the region associated with a destination address.
  • GEOSITE relies on a domain-category database; available categories depend on the current mihomo version and data files.
  • MATCH catches traffic not matched earlier and should be placed at the end of the rule list.

no-resolve prevents an IP rule from triggering an extra DNS lookup solely for matching. It is often used with LAN subnets or GEOIP rules, but whether to add it depends on the DNS mode and rule requirements above. Adding it to a domain rule has no effect.

Typical symptoms of incorrect rule order

  1. Putting MATCH in the middle means rules below it never run.
  2. Writing a broad DOMAIN-KEYWORD rule first prevents later exact-domain rules from matching.
  3. If a LAN subnet is not sent DIRECT early enough, traffic to routers, NAS devices, or development servers may be routed through the proxy.
  4. The target name was changed, but the rule table still references the old proxy group, so loading reports a missing proxy or policy.
  5. Using GEOSITE or GEOIP without the corresponding database can cause rule loading or matching failures.

TUN and profile: common trailing settings

TUN mode takes over more system traffic through a virtual network interface, useful for apps that cannot read system proxy settings. It does not conflict with mixed-port: TUN works at the network layer, while mixed-port remains available to apps that support HTTP or SOCKS5.

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

profile:
  store-selected: true
  store-fake-ip: true

auto-route lets the core configure routes automatically, while auto-detect-interface identifies the current outbound network interface. TUN driver, administrator-permission, and routing requirements vary by operating system. GUI clients commonly generate and manage these settings under “Settings” → “Network” or “Settings” → “TUN Mode.” If the client already manages TUN, do not declare the same fields repeatedly across multiple override layers.

store-selected: true saves the proxy-group selection so the previously selected item is restored after restart. store-fake-ip: true saves Fake-IP mappings, helping reduce connection interruptions caused by changed mappings after restart. Both fields belong to profile, not to dns.

A complete check order, from loading to matching

Passing YAML syntax validation does not guarantee that a node can connect; a reachable node does not guarantee that DNS and rules work as intended. Troubleshoot in a fixed order instead of changing several sections at once to isolate problems more reliably.

  1. Check YAML parsing. Start on the client’s config page or in the core log and confirm there are no indentation errors, duplicate keys, unknown fields, or type mismatches.
  2. Check local listeners. Confirm that enabled ports such as 7890, 7891, 7893, 9090, and 1053 are not occupied by another process.
  3. Check the node handshake. Select one node on the proxy page and run a latency test, then review logs for TLS, authentication, timeout, or unreachable-network errors.
  4. Check proxy-group references. Confirm that rule targets, group members, and provider names match exactly.
  5. Check DNS. Watch for DNS query timeouts and verify that the DoH server hostname can be initially resolved through default-nameserver.
  6. Check rule matches. Open the connections or logs page to see which rule matched the destination domain and which proxy group and node were ultimately selected.
  7. Enable TUN last. Confirm that the regular system proxy works first, then enable TUN to distinguish node issues from routing takeover issues.

A practical route for reading a config

When reading an unfamiliar config, start with the top-level ports, then inspect dns, proxies or proxy-providers, proxy-groups, and rules, followed by tun and profile. This mirrors traffic processing: an application enters through a local port or TUN, DNS resolves the domain, rules choose a proxy group, and the group selects a node.

Maintainability depends less on the number of fields than on clear references. Node names, provider names, proxy-group names, and rule targets form one continuous chain. Whenever a name changes, follow the chain and check every later reference. After editing, reload the config with the client’s validation tool and confirm the actual match through connection logs.

Download the desktop client Windows, macOS, Android, iOS, Linux