Clash config.yaml Explained: Ports, DNS, Proxy Groups, and Rules
Follow a complete config.yaml from top to bottom. Learn what each section does, how sections reference one another, and where configuration mistakes commonly occur.
Check the core and configuration source first
config.yaml is a configuration file read by the proxy core. The core establishes connections and routes traffic; the client provides an interface for importing and switching configurations and viewing logs. A client may merge port settings or override rules before loading, so the file you edit may not contain everything that ultimately takes effect.
This guide focuses on common mihomo fields, including those from the former Clash Meta core. Traditional Clash and mihomo share some syntax, but not every feature is interchangeable—especially TUN, DNS, and newer proxy protocols. Check the core name and version in the client's About or core information page, then consult the documentation for that version. Don't assume compatibility just because the window says Clash.
Keep three things in view as you read
- Ingress: Ports and TUN determine how traffic enters the core.
- Egress:
proxiesdefines connections, whileproxy-groupsorganizes them into selectable groups. - Routing:
rulesroutes connections to a proxy group or built-in action based on conditions such as domain or IP.
The top-to-bottom order is mainly for readability. The top-level rules section doesn't need to sit next to the proxy groups it references. What matters is that names match, fields are nested correctly, and rules appear in the right order within the list.
A complete config.yaml you can inspect
Here is a mihomo configuration for reading and local testing. It has no remote proxy nodes, so all connections allowed through are sent directly; it can't be used to check whether a remote proxy works. This keeps the focus on how ports, DNS, proxy groups, and rules fit together without introducing unreachable demo servers.
# Local proxy entry points
mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
# Runtime mode and logging
mode: rule
log-level: info
ipv6: false
# Local DNS service
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: redir-host
nameserver:
- 223.5.5.5
- 1.1.1.1
# TUN is disabled for now
tun:
enable: false
# No remote proxy nodes
proxies: []
# The proxy group uses the built-in DIRECT action
proxy-groups:
- name: "Proxy Selection"
type: select
proxies:
- DIRECT
# Rules are checked top to bottom; the last rule is the fallback
rules:
- DOMAIN-SUFFIX,example.com,Proxy Selection
- IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
- IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- MATCH,Proxy Selection
example.com is a reserved example domain used here to demonstrate a domain rule. The two DNS servers are specific public resolvers and may not be reachable on every network. Before loading the configuration, make sure no other application is using local ports 7890 or 1053.
Read YAML indentation before looking at the fields
YAML indentation shows which fields belong to which section. This example consistently uses two spaces; avoid tabs. dns: starts at the top level, while enable: is indented one level to show that it belongs to the DNS configuration. A - introduces a list item; [] denotes an empty list.
- Leave a space after the colon, as in
mode: rule. - Use consistent indentation for fields at the same level. Don't indent top-level
rules:under a proxy group. - Quote strings containing special characters such as
#so the rest of the line isn't treated as a comment. - Don't define
dnsorrulesmore than once at the same level. Some parsers reject duplicate keys; others keep only one of them.
Ports and mode: connect apps to the right entry point
mixed-port: 7890 accepts both HTTP proxy and SOCKS5 connections on the same port. To configure an app to use the proxy manually, enter 127.0.0.1 as the address and 7890 as the port, then choose the protocol supported by the app. These are example values, not fixed defaults for every client.
| Field | Purpose | What it means here |
|---|---|---|
mixed-port | Shared HTTP and SOCKS entry point | Local port 7890 |
port | Separate HTTP proxy entry point | Not set in this example |
socks-port | Separate SOCKS proxy entry point | Not set in this example |
allow-lan | Allow devices on the local network to connect | false; local connections only |
mode | Choose how traffic is routed | rule: route traffic according to rules |
mode: rule enables the rule-based mode covered here. Global mode generally sends traffic through the global policy, while direct mode connects without using a proxy. In either mode, changing regular rules won't have the expected effect. If the client overrides the mode, the actual runtime state is what matters.
log-level: info is suitable for routine monitoring. To investigate an issue, temporarily switch to debug, reproduce it, then switch back. Detailed logs may contain visited domain names, so remove sensitive information before sharing them.
DNS and TUN: treat name resolution and traffic capture separately
DNS resolves domain names to IP addresses. This example enables the core's DNS service and listens on 127.0.0.1:1053; that doesn't automatically send every DNS request from the operating system to this service. The actual path depends on system settings, client integration, and whether TUN is capturing traffic.
nameserver and DNS modes
nameserver is the list of upstream servers used for DNS resolution. The plain IP addresses in this example use regular DNS without encryption. For DoH (DNS over HTTPS), configure a server address using syntax supported by your core version, and check its connection route and bootstrap DNS requirements.
enhanced-mode: redir-host returns real addresses in DNS responses. Another common mode, fake-ip, returns virtual addresses mapped by the core back to domain names. These aren't speed settings. After switching modes, old DNS cache entries and existing connections may affect what you observe; clear the cache and restart affected apps if needed.
TUN isn't another proxy node
TUN is a virtual network interface that receives traffic routed to it by the operating system. The example only sets tun.enable: false, so this traffic-capture path is disabled. Enabling the system proxy doesn't enable TUN: the system proxy mainly affects apps that follow the OS proxy settings, while TUN can capture more traffic when routing and permissions are configured correctly.
- First test an app's manual proxy setting with
127.0.0.1:7890, then test the system proxy, and only consider TUN after that. - If you need TUN, follow your client's and operating system's requirements for administrator privileges, virtual interfaces, and routing.
dns-hijackcaptures matching DNS traffic, but it doesn't work for every type of encrypted DNS. An app's built-in DoH may use a separate connection.- IPv6 is disabled in this example to narrow down troubleshooting; that doesn't make it a suitable permanent setting for every network.
proxies and proxy groups: trace the route by name
proxies is the list of individual proxy connections. A real node typically includes a name, protocol type, server, port, and authentication parameters. Each protocol may require additional fields. Server addresses and passwords must come from the actual service configuration; don't combine fields from different protocols to create a node.
The proxies: [] entry explicitly means there are no remote nodes in this example. DIRECT is a built-in action for connecting directly and doesn't need to be declared in the node list. Similarly, REJECT is a built-in action that rejects connections.
select lets you choose; it doesn't test latency
proxy-groups organizes one or more egress options into groups. The example's type: select means you choose manually, and the group is named “Proxy Selection.” When you add real nodes, include their exact names in the group's proxies list to make them available for selection.
“Proxy Selection” in rules
↓ Names must match
The group whose name is “Proxy Selection” under proxy-groups
↓ Currently selected option
DIRECT, meaning connect to the destination directly
url-test is the proxy group type that selects an egress based on test results; it needs a suitable test URL and interval. A latency test measures the response to one specific destination, not download bandwidth, and doesn't guarantee that every site will load.
Subscriptions may also include proxy-providers, which loads a collection of nodes from a file or remote source. Proxy groups usually reference a provider by name using use, rather than adding the provider name as if it were a single node in proxies. For this type of configuration, also check the source, update path, and health check settings.
rules: read from the first entry through MATCH
Rules are generally checked in list order, and the first match determines where a connection goes. Put specific conditions first, broader ones later, and the fallback last. If MATCH is the first rule, the remaining rules won't get a chance to handle new connections.
| Rule snippet | Matches | Action |
|---|---|---|
DOMAIN-SUFFIX,example.com | example.com and its subdomains | Proxy Selection |
IP-CIDR,127.0.0.0/8 | IPv4 loopback range | DIRECT |
IP-CIDR,10.0.0.0/8 | Private IP ranges starting with 10 | DIRECT |
IP-CIDR,172.16.0.0/12 | Private IP range 172.16–172.31 | DIRECT |
IP-CIDR,192.168.0.0/16 | Private IP ranges starting with 192.168 | DIRECT |
MATCH | Connections not matched by an earlier rule | Proxy Selection |
Keep domain rules and IP rules distinct
DOMAIN matches an exact domain; DOMAIN-SUFFIX matches a domain and its subdomains. Enter a domain in the rule, not a full URL. For example, https://example.com/path includes a protocol and path, so it can't be used directly as a domain condition.
In IP-CIDR, CIDR notation describes an IP range using a prefix length. The trailing no-resolve means the core shouldn't initiate a domain lookup to check this IP rule; it can still match if the connection metadata already includes a destination IP. It does not disable DNS altogether.
This example lists only some common local subnets, not a complete set of rules for special addresses. If you can't reach a printer, router, or corporate intranet, check the actual destination address and rule match logs. Don't assume every private network uses only 192.168.0.0/16.
For RULE-SET, follow the reference to its rule provider
RULE-SET refers to a rule collection defined under rule-providers, not a collection of proxy nodes. Check the provider name, source, format, and behavior type. A successful download only confirms that the content was retrieved; it doesn't mean the content format is suitable for the current configuration.
Check and verify the configuration before use
Passing a syntax check doesn't mean the network is working as expected. Break validation into four steps: the config loads, the core listens, rules match, and connections succeed. Change one thing at a time so it's easier to return to the last working state if something goes wrong.
- Check the file. Save a test copy as UTF-8
config.yamland make sure its extension hasn't become.yaml.txt. Check indentation, duplicate keys, and proxy group names. - Validate the core configuration. Use your client's built-in check, or run the test command below in an environment with the mihomo command-line program installed. In the current Windows directory, the executable is usually written as
.\mihomo.exe. - Load the configuration and check the logs. Look for syntax errors, missing proxy groups, or port-in-use warnings. If the client rewrites the configuration, inspect the configuration it actually generates as well.
- Send a request through a specific entry point. Specify the proxy port explicitly first to rule out interference from system proxy settings or browser configuration.
- Check the connection records. Confirm the matched rule, proxy group, and final egress for the test connection, then re-enable your original DNS or TUN settings one at a time.
# Validate the configuration; this command does not start a long-running proxy service
mihomo -t -f ./config.yaml
# After the configuration loads and the core is running, test the local HTTP proxy entry point
curl --proxy http://127.0.0.1:7890 --head https://example.com
The second command tests the route from the local proxy entry point to the example site. Because this example ultimately uses DIRECT, a successful request doesn't prove that a remote proxy node works. On Windows, if the terminal treats curl as a different command, run the installed curl.exe explicitly.
Use the same reading order for future maintenance: entry point settings, runtime mode, DNS, traffic capture, nodes, proxy groups, and rules. For detailed field descriptions, see this site's YAML manual. For the steps to import and enable a configuration, see the user guide. Keeping a verified configuration is easier than rewriting one from scratch every time something goes wrong.