Clash config.yaml Explained: From port to rules

Explore the five main sections of a Clash config.yaml file—general settings, dns, proxies, proxy-groups, and rules—in order, with notes on YAML indentation and cross-section references.

Start with the structure: how the five sections fit together

When reading a config, check the entry point first, then DNS, nodes, proxy groups, and rules. A config.yaml file isn't a script that runs line by line: top-level fields can usually be rearranged, but the order within lists can directly affect behavior, especially in rules. Organizing the file into five sections makes it easier to read and troubleshoot; it doesn't mean the core processes them in five sequential stages.

This guide primarily uses the mihomo core with the Clash configuration format. The Clash client provides the graphical interface, while the core parses the config and handles connections. Clients may also merge or override settings such as ports, DNS, and TUN. Before editing, check which core is in use and whether you're changing the original subscription file, an override file, or the final runtime config passed to the core by the client.

SectionMain purposeReferences
General settingsSet listening ports, operating mode, and log levelApp proxy settings and client toggles
dnsConfigure how the core resolves DNS and which upstreams it usesDomain resolution, Fake-IP, and DNS interception
proxiesDefine connection settings for proxy nodesNames of members in proxy groups
proxy-groupsOrganize nodes and other policies into selectable groupsTarget names used in rules
rulesMatch connections in order and specify how to handle themProxy groups, nodes, or built-in policies

The most common reference chain is: rules point to a proxy group, which then references node names; each node provides a server address, port, and authentication details. DIRECT and REJECT are built-in policies and don't need to be defined separately under proxies.

General settings: ports, mode, and listening scope

Three proxy ports don't mean three nodes

port is the HTTP proxy listening port and also supports standard HTTPS CONNECT tunnels; socks-port is the SOCKS proxy listening port; mixed-port accepts both HTTP and SOCKS proxy requests on the same port. These are local entry points, unrelated to the remote node's port.

port: 7890
socks-port: 7891
mixed-port: 7892
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false

This config uses three different ports to show how the fields relate; you don't need to enable all of them. If you only need a mixed listener, you can keep just mixed-port: 7892. Set your browser or system HTTP proxy to 127.0.0.1:7892; apps that support SOCKS can use the same mixed port. After changing the core's port, update the app settings too—otherwise, the app may keep connecting to the old 7890 port.

What do mode and allow-lan control?

  • mode: rule: Routes traffic according to the rules list, useful for choosing different exits by domain or IP in everyday use.
  • mode: global: Routes traffic primarily through the selected global policy instead of applying the regular rules list one by one.
  • mode: direct: Uses direct mode. It doesn't disable the client or clear the system proxy settings.
  • allow-lan: false: Doesn't expose the proxy listener to devices on your local network. If you need to share it, configure the listening address, authentication, and firewall rules as well.

dns: upstream resolution and traffic interception

The dns section configures domain resolution in the core, but enabling the core's DNS and routing all system DNS requests through it are two different things. This example starts a DNS listener on local port 1053, uses Fake-IP mode, and specifies a standard DNS upstream:

dns:
  enable: true
  listen: "127.0.0.1:1053"
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - 223.5.5.5
  fake-ip-filter:
    - "*.lan"
    - "localhost"

Four fields to keep straight

  • listen is the address and port where the core accepts DNS queries, not the upstream server address. Standard system DNS settings usually can't specify a custom port such as 1053.
  • nameserver specifies the DNS upstream. This example uses standard DNS; whether it's reachable and returns suitable results depends on your network.
  • enhanced-mode: fake-ip makes the core return virtual IP addresses where applicable and maintain a domain-to-IP mapping. These aren't the websites' real public IP addresses.
  • fake-ip-filter specifies domains that should not receive Fake-IP responses, for local network names or specific compatibility needs.

With TUN, the client or config must also route DNS requests to the core through settings such as DNS hijacking or route interception. Setting dns.enable: true alone doesn't change system routing; enabling the system proxy alone doesn't guarantee that every app's DNS queries go through the core. Apps with their own encrypted DNS may also use a separate resolution path.

If you switch the upstream to a DoH URL with a hostname, such as https://dns.alidns.com/dns-query, consider how that hostname itself will be resolved. In mihomo, default-nameserver can be used for bootstrap resolution, while proxy-server-nameserver resolves proxy node hostnames. These fields aren't interchangeable, and adding multiple layers of DNS forwarding without understanding the connection path can cause problems.

proxies: node definitions and subscription boundaries

proxies is a list of proxy nodes. Each node typically includes name, type, server, and port; other authentication and transport fields depend on the protocol. A node's remote port may be 443 or another value specified by the server. Don't change it to 7890 just because the local proxy listens on 7890.

Check where each node setting comes from

  1. First, make sure type matches the server protocol. Supported protocols depend on the core version; being able to import a config doesn't mean every protocol will connect successfully.
  2. Use the settings provided by your service—such as the server address, password, UUID, and encryption method. Don't guess based on field names.
  3. The transport layer, TLS settings, and certificate name must match the server. If you get a certificate error, check the domain and system time first instead of disabling certificate verification.
  4. It's best to give each name a unique value. Proxy groups reference nodes by name, so update those references if you rename a node.

A valid config can have no nodes: proxies: [] defines an empty list. This is useful for checking the file structure, but it won't create a proxy exit. The complete example below uses an empty list and DIRECT, so it only demonstrates config loading and rule references.

proxy-groups: name references and policy selection

A proxy group collects nodes, built-in policies, or other groups into a selectable exit. The example below defines a manual selection group with only the built-in DIRECT and REJECT members, so it doesn't require any node credentials:

proxy-groups:
  - name: "Exit selection"
    type: select
    proxies:
      - DIRECT
      - REJECT

type: select lets you choose a member manually. Select DIRECT on the client's proxy page and rules that point to “Exit selection” will use a direct connection. Select REJECT and those connections will be blocked. The rule itself remains in place; its behavior changes based on the selected group member.

Three common proxy group types

TypePurposeWhat to check
selectChoose a member manuallyThe member exists and the current selection is as expected
url-testAutomatically choose based on connectivity testsTest URL, interval, and candidate node availability
fallbackChoose an available member based on candidate orderMember order and health-check settings

Automatic test results measure connectivity to a specific test URL; they don't represent real-world download speeds across all websites. If you're just learning the structure, start with select to verify the reference chain. When nesting groups, avoid circular references—for example, group A referencing B while B references A.

If your config uses proxy-providers, groups typically reference provider names with use rather than putting provider names in the proxies list. These fields refer to different types of objects. If you see a “proxy not found” error, first check whether the reference points to a node, a proxy group, or a node provider.

rules: match specific traffic first, then add a fallback

In rule mode, connections are checked against the list in order, and the target of the first matching rule is used. Policy names in the config must match their definitions exactly, including capitalization, spaces, and non-Latin characters. These four rules handle local network domains, an example domain, private IP addresses, and all remaining connections:

rules:
  - DOMAIN-SUFFIX,lan,DIRECT
  - DOMAIN-SUFFIX,example.org,Exit selection
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - MATCH,Exit selection
  • DOMAIN-SUFFIX,lan,DIRECT matches lan and its subdomains, not any string that happens to contain “lan.”
  • DOMAIN-SUFFIX,example.org,Exit selection sends the example domain and its subdomains to “Exit selection.” example.org is used here to demonstrate rule syntax.
  • IP-CIDR,192.168.0.0/16,DIRECT,no-resolve matches this private IPv4 range. no-resolve means the rule won't actively resolve a domain just to check for a match.
  • MATCH,Exit selection catches connections that didn't match an earlier rule, so it belongs at the end of the list.

no-resolve doesn't disable DNS for the whole config or guarantee that no resolution ever occurs. It only affects whether the relevant IP-based rule actively triggers a lookup. Connections that already have a destination IP can still be matched against IP rules.

If you put MATCH,DIRECT on the first line, later rules can't handle connections it has already matched. For more specific domain exceptions, put them before broader suffix rules. If you use GEOIP, GEOSITE, or RULE-SET, also check that the required geo database or rule provider is available. Don't copy a rule without checking where its data comes from.

Complete structure: two-space indentation and a minimal config

This config has no external nodes and sends matching traffic to a proxy group whose only member is DIRECT. Use it to check YAML structure, listening ports, and group references; it isn't a subscription that provides remote proxy access, and it doesn't enable TUN. The core's DNS listener is at 127.0.0.1:1053; additional system or client settings are still needed to receive system DNS queries.

mixed-port: 7890
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false

dns:
  enable: true
  listen: "127.0.0.1:1053"
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - 223.5.5.5
  fake-ip-filter:
    - "*.lan"
    - "localhost"

proxies: []

proxy-groups:
  - name: "Exit selection"
    type: select
    proxies:
      - DIRECT

rules:
  - DOMAIN-SUFFIX,lan,DIRECT
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - MATCH,Exit selection

Four common YAML mistakes

  1. Indenting with tabs. Use spaces consistently; add two spaces at each level, as shown above. Fields at the same level must line up.
  2. Indenting a top-level field under the previous section. proxies, proxy-groups, and rules must start at the beginning of the line, not under dns.
  3. Leaving out a list item's hyphen. nameserver, proxy group members, and rules are lists; start each item with - .
  4. Defining the same top-level key more than once. Don't append a second dns section or another rules section at the end of the file. Add changes to the original section instead; parsers may handle duplicate keys differently.

If a name contains special characters such as # or a colon followed by a space, quote it to avoid having it interpreted as a comment or mapping syntax. Typical rule strings don't need quotes just because a name contains non-Latin characters, though quoting the entire string is also fine. Don't use a full-width colon from a webpage in place of YAML's standard colon, :.

Validate the config: from syntax to live connections

Saving the config only means the editor wrote the file. A successful load by the core only means the structure and required fields passed validation. You still need to test node connectivity, DNS routing, and whether apps are using the proxy.

A four-step checklist

  1. Back up a working config, make a separate copy named config.yaml, and edit that copy. Change one section at a time so you can roll back easily.
  2. Test the config with the mihomo binary that's actually running. On Linux or macOS, if the binary is in the current directory, run the command below.
  3. Reload or enable the config in the client, then check the logs for errors such as a port conflict, a missing name reference, or unavailable rule data.
  4. Test the listener with a request that explicitly uses the proxy, then check the client's connection log for the matched rule and policy chain. Only after that should you test system proxy or TUN-wide routing.
./mihomo -t -f ./config.yaml

curl --proxy http://127.0.0.1:7890 --head https://example.org/

If the config depends on relative paths for rule files, node providers, or databases, run the test from the same working directory used at runtime. You can use the core's -d option to specify the config working directory. If the command isn't found, check the binary path first rather than changing YAML fields. The curl request above only tests the specified HTTP proxy listener and destination; it doesn't prove that UDP, system DNS, or TUN is working.

Download ClashChoose a client for your platform