1. Check the config source, core, and YAML structure

config.yaml is a common configuration filename, but not every client uses it. Subscription downloads, local configs, and client-generated runtime configs may be stored in different locations. Before editing, check the client's config list to identify the active item, then inspect the runtime config. Editing an inactive file won't change the current connection.

Clash is a proxy configuration ecosystem; Clash Meta later adopted the name mihomo. Many core fields remain compatible, but protocol support, DNS options, and TUN settings vary by core and version. This guide covers the common structure first, then calls out mihomo-specific extensions. Client interfaces use different names, so the app icon alone won't tell you which core is running.

Three things to look for in YAML

  • Indentation shows nesting. This guide uses two spaces, never tabs. Top-level keys like dns, proxies, and rules start in the same column.
  • A colon separates each key and value. Write mode: rule, not with a non-ASCII colon. A - at the start of a line marks a list item.
  • Names are references. Every policy group used by a rule must exist, and every node or other group referenced by a group must also be defined.

2. Ports and modes: decide how traffic reaches the core

Near the top of the file, you'll usually find listener ports, the operating mode, and the log level. Ports accept requests; the mode determines how the core selects an outbound route. These are separate steps: even correct rules won't proxy traffic if the app doesn't send it to the client.

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false
FieldWhat the example meansWhat to check
mixed-portAccepts both HTTP and SOCKS proxy requests on port 7890The port configured in the app must match and must not be in use by another process
allow-lanfalse means other devices on the local network cannot connectWhen sharing access, also check the listening address and firewall
moderule routes connections according to the rules listGlobal mode can't be used to verify rule matching order
log-levelinfo logs routine runtime detailsSwitch to debug temporarily for troubleshooting, then switch back
ipv6false disables IPv6 support in the relevant core componentIt does not disable all IPv6 traffic on the operating system

Choosing between mixed-port, port, and socks-port

port is the HTTP proxy port; socks-port is the SOCKS proxy port. Use mixed-port when you want a single entry point for both. For example, if an app is configured to use the HTTP proxy at 127.0.0.1:7890, the core must accept the corresponding requests on port 7890. Don't assign the same address and port to multiple listeners.

mode: rule routes traffic according to rules; global uses a global policy; direct connects directly. Changing modes doesn't automatically change your browser's system proxy settings. For an initial test, use the system proxy and enable TUN only after basic connectivity works. This avoids troubleshooting multiple traffic paths at once.

If you see external-controller: 127.0.0.1:9090, that's usually the listening address for the control API, not the proxy port. Don't enter 9090 in your browser's proxy settings, and don't expose the control interface to the public internet for convenience.

3. dns: understand resolvers, the listening address, and fake-ip

dns controls how the core handles DNS requests sent to it. The example below uses redir-host to explain the basics; the two IPs are sample DNS servers, not universal recommendations. Before using them, make sure they're reachable on your network and consider your DNS privacy requirements.

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: redir-host
  nameserver:
    - 223.5.5.5
    - 119.29.29.29
  • enable: true enables the core's DNS feature, but doesn't automatically route every system DNS request through the core.
  • listen sets the local DNS listening address. The example uses port 1053, not the commonly used system port 53. Without additional forwarding, the system won't automatically query this port.
  • nameserver lists upstream DNS resolvers. Traditional DNS usually uses port 53; DoH and DoT use their respective protocol endpoints.
  • dns.ipv6: false controls how this DNS module handles AAAA queries; it is not an operating-system IPv6 firewall.

Why does fake-ip return an address starting with 198.18?

enhanced-mode: fake-ip assigns a mapped address to each domain, then the core associates connections with the original domain. A common setting like fake-ip-range: 198.18.0.1/16 is used for this mapping; it isn't the website server's actual public IP address. Seeing an address in this range doesn't by itself mean DNS has been poisoned.

Some local network services, device discovery features, or apps that rely on real resolved addresses may need exceptions. Configure fake-ip-filter for the specific issue instead of adding a large number of broad domain patterns. Behavior differs between redir-host and fake-ip; after switching, start a new connection before testing.

mihomo: pay attention to how proxy server hostnames are resolved

Proxy servers may also be specified by hostname. mihomo offers fields such as proxy-server-nameserver to control how node hostnames are resolved. If an upstream DoH endpoint is itself a hostname, bootstrap resolution may also involve default-nameserver. If resolving a node's hostname requires the proxy, while establishing the proxy requires that hostname, you have a circular dependency. If every node times out after startup, check the logs for DNS resolution errors before changing rules.

4. proxies: node settings aren't subscription links

proxies is a list of node definitions. A node typically has name, type, server, and port; authentication and transport fields depend on the protocol. Policy groups refer to nodes by name. The server port is on the remote host, so don't confuse it with local port 7890.

This guide doesn't invent server addresses or passwords. To understand the structure, use proxies: [] for an empty node list, then temporarily point a policy group to the built-in DIRECT. This demonstrates direct routing, but it doesn't provide a proxy service. For actual proxying, add node settings supplied by your service provider and supported by your current core.

Where should you add a subscription URL?

  • Full configuration subscription: Import it from the client's subscription or config page. The response may already include nodes, policy groups, and rules.
  • Node collection subscription: A supported proxy-providers feature can load it, and policy groups can reference it with use.
  • Single-node share link: The client must recognize or convert it. You can't paste it directly into proxies as a YAML node object.

A regular web page, login page, or expired-subscription notice isn't a node list. If importing fails to parse, check the response content before changing indentation over and over. Also distinguish a full config from the node collection format expected by a provider: sharing a .yaml extension doesn't make their internal structures interchangeable.

With proxy-providers, interval: 3600 commonly means the provider updates every 3,600 seconds. In a policy group's health check, interval: 300 means checks run every 300 seconds. These settings serve different purposes; neither is a latency threshold or a replacement for the client's full-subscription update settings.

5. proxy-groups: organize nodes into selectable routes

Rules usually point to a policy group, which then selects a node or another outbound route. That way, you can change nodes without editing every rule. The group below is named "Outbound" and contains only the built-in direct route, making it useful for checking references.

proxies: []

proxy-groups:
  - name: Outbound
    type: select
    proxies:
      - DIRECT

Three common policy group types

TypeHow it selects a routeWhat to keep in mind
selectChoose a route in the group manuallyUseful for pinning a node while troubleshooting rules and connectivity
url-testAutomatically selects a low-latency route based on test resultsThe response time of the test URL isn't the same as download speed
fallbackSelects the first available route in the listPriority follows the list order, not lowest latency

url-test and fallback usually also need settings such as a test URL and check interval. The URL must be reachable from your current environment; if the test site is down, several working nodes may all appear unavailable. Don't delete nodes based on a single latency test.

Keep group and node names unique and clear. If a rule points to "Outbound" and you rename the group to "Proxy Egress," update the rule too. Groups can be nested, but avoid circular references: if A points to B and B points back to A, route selection can't complete correctly.

6. rules: match from top to bottom; put MATCH last

In rule mode, connections are generally checked against the list in order, and the first matching rule determines the policy. More specific rules don't automatically take priority: a broad rule near the top may prevent a later, precise rule from ever running. An easy-to-check order is to put specific exceptions first, broader rules next, and the catch-all last.

rules:
  - DOMAIN,example.com,Outbound
  - DOMAIN-SUFFIX,example.org,DIRECT
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
  - MATCH,Outbound
  • DOMAIN matches an exact domain. The example matches only example.com; it doesn't automatically include all its subdomains.
  • DOMAIN-SUFFIX matches the domain and its subdomains. The example includes example.org and www.example.org.
  • IP-CIDR matches a destination IP range. The example lists three common private IPv4 ranges, not a complete list of all special-use addresses.
  • no-resolve means don't actively resolve a domain just to match this IP rule; it doesn't disable DNS for the entire connection.
  • MATCH catches connections that didn't match earlier rules, so put it at the end of the list.

GEOIP, RULE-SET, and rule providers

GEOIP,CN,DIRECT matches based on an IP geolocation database, not on the domain's text. A missing or outdated database, a failed update, or an IP geolocated to a different region can all affect the result. If you encounter a database error, continue with the GEOIP checks in Troubleshooting.

RULE-SET refers to a rule collection defined in rule-providers. It is not the same as proxy-providers, which stores nodes. Before using a rule collection, check its format, behavior type, and compatibility with your core. After importing one, you still need to reference it in rules; defining the resource alone doesn't make it part of rule matching.

7. Build a minimal config, then add TUN and subscription nodes

The example below combines the basic fields into a local learning config. It has no proxy servers, so every route ultimately connects directly. Use it to verify YAML nesting, listening ports, and policy references. If the client automatically overrides ports or DNS, trust the runtime config and logs.

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: redir-host
  nameserver:
    - 223.5.5.5
    - 119.29.29.29

proxies: []

proxy-groups:
  - name: Outbound
    type: select
    proxies:
      - DIRECT

rules:
  - DOMAIN,example.com,Outbound
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - MATCH,Outbound

Why leave TUN out for now?

TUN is a separate way to capture traffic, not a proxy node or a switch that makes rules work automatically. Common mihomo settings include tun.enable, stack, auto-route, and dns-hijack, but the results also depend on the operating system, service permissions, network adapter, and routing environment. Don't copy a TUN config written for an unspecified platform to every device.

First verify the path from app proxy to port 7890, then through the rules to the outbound route. Enable TUN afterward using a method supported by your client. If the internet stops working, check routing, DNS interception, and conflicts with other VPNs before rewriting proxies. For basic setup, see the TUN mode guide in Getting Started.

8. Config changes not taking effect? Check syntax, references, and runtime status

  1. Make sure you're editing the active config. Check the selected item and its last-updated time in the config list, then reload it. A client may store multiple files with the same name.
  2. Check the line reported in the syntax error. For a yaml: line message, inspect that line and the one above it for colons, quotes, list markers, and indentation. Quote passwords containing special characters according to YAML string syntax.
  3. Check for duplicate top-level keys. Don't append a second dns: or rules: at the end of the file. Duplicate keys may be rejected or may overwrite each other, depending on the parser.
  4. Check outbound references. If you see an error saying a proxy or policy doesn't exist, compare group names, node names, and capitalization character by character. Valid YAML syntax doesn't guarantee valid references.
  5. Check listeners and traffic entry points. If you see address already in use, check whether port 7890 or the DNS listening port is already occupied. Changing the system proxy address won't resolve a port conflict.
  6. Check which rule actually matched. Make sure the core is in rule mode, then inspect a new connection's rule details. If an app bypasses the system proxy, fix the traffic entry point or use TUN if needed.

Test the config with the core's built-in checker

If you can run mihomo from the command line, execute the command below from the config directory. Config tests may also need external resources and databases, so use the same working directory and resource environment as the actual runtime.

mihomo -t -f config.yaml

A passing test means the core accepted the config; it doesn't prove node credentials are valid, all upstreams are reachable, or a website used the intended route. Check the connection logs next. During troubleshooting, change one thing at a time and record the errors before and after. This usually makes the cause easier to find than changing DNS, rules, and TUN all at once.

The key to understanding a config is to trace each layer: entry port → DNS resolution → rule match → policy group → final route. For more rule troubleshooting, see config.yaml checks. Before switching clients, check which core the new client uses and which fields it supports, then migrate your config.