Advanced Config 12 min read

Clash YAML Config Explained: From mixed-port to rules

A field-by-field guide to ports, DNS, proxies, proxy-groups, rule-providers, and rules, with examples of common indentation errors.

1. Configuration structure: separate client settings from core config

The mihomo core used by Clash Verge Rev handles connections, DNS, and rule matching. YAML is the format used to write the configuration, not a proxy protocol. A file that passes YAML parsing is only syntactically valid; the core still needs to check whether node types are supported and referenced policy groups exist.

When reading a subscription config, follow this order: “inbound ports → DNS → proxies → proxy groups → rule sets → matching rules.” The configuration is not executed from top to bottom. For example, rules can reference a policy group defined earlier, and that group can reference proxies. These names link the different parts of the config.

  • Top-level fields such as mixed-port and mode set the local inbound port and operating mode.
  • dns is a mapping that contains settings for enabling DNS, choosing a resolution mode, and specifying upstream servers.
  • proxies, proxy-groups, and rules are lists, with each item prefixed by a hyphen.
  • rule-providers is a named mapping used to define external rule sets.

2. mixed-port: set the local inbound port for apps

mixed-port accepts both HTTP and SOCKS proxy connections on a single port. The example below uses 7897; this value is not fixed across all installations. Use the listening port currently shown in your client.

mixed-port: 7897
allow-lan: false
mode: rule
log-level: info
ipv6: false
FieldExample meaningWhat to check
mixed-port: 7897Local mixed-proxy inbound port is 7897Enter this port in apps where you configure the proxy manually
allow-lan: falseDoes not allow connections from devices on the local networkUsually leave this off when using the proxy on this device only
mode: ruleChoose the outbound based on rulesIn Global mode, you can't use rules to verify traffic routing
log-level: infoLog routine runtime informationTemporarily switch to debug for troubleshooting, then switch back
ipv6: falseDisables IPv6 support in the coreDoes not disable IPv6 in the operating system

For a manually configured HTTP proxy, set the host to 127.0.0.1 and the port to 7897. If the client is changed to 7898, update these manual settings too. When the client manages the system proxy, apply the config and then verify the actual system settings.

The mixed port is neither a DNS port nor a core control interface. Don't enter the external-controller address in your browser's proxy settings. To share the proxy with devices on your local network, also check the listening address, firewall, and access authentication. Setting allow-lan to true alone is not enough.

3. dns: resolution mode, upstream servers, and traffic interception

dns controls the core’s DNS module. Enabling it does not mean every DNS request from the operating system is routed through the client. System DNS settings, secure DNS in apps, and TUN DNS hijacking can all affect the request path. First find out where requests are going, then adjust the upstream servers.

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - https://1.1.1.1/dns-query
    - https://1.0.0.1/dns-query

fake-ip returns a mapped address

fake-ip assigns a mapped address to a domain. The core keeps track of the domain-to-address mapping for handling subsequent connections. If you see an address starting with 198.18, don't assume DNS has been tampered with. This address range is reserved for testing and does not represent a website's real public IP address.

Listening on port 1053 does not automatically change system DNS

listen: 127.0.0.1:1053 means the local DNS server listens on port 1053. Standard system DNS settings usually accept only a server IP address and don't let you specify a custom port, so entering 127.0.0.1 alone won't make requests go to port 1053. In TUN mode, check the client-generated tun and dns-hijack settings to confirm how DNS traffic is intercepted.

  • nameserver specifies the upstream servers the core uses for resolution. This example uses two specific DoH URLs; whether they are reachable depends on your network.
  • When using an encrypted DNS URL that contains a hostname, you may also need default-nameserver to bootstrap resolution of the upstream server's hostname.
  • If a device or app doesn't work with fake-ip, check fake-ip-filter for the affected domain rather than disabling all DNS handling first.

If your subscription already includes a complete DNS configuration, don't replace it with this snippet. The original may include DNS resolution for proxy hostnames, policies for domains in and outside mainland China, or handling for specific domains. Change one setting at a time while keeping logs from before and after, so you can identify the cause of any difference.

4. proxies and proxy-groups: node settings and outbound selection

proxies defines the connection settings for individual nodes. proxy-groups organizes nodes into manual selection, latency testing, or other policies. Node names are identifiers used elsewhere in the config, not descriptive labels; preserve their spacing, capitalization, and characters exactly.

The example below shows only the field structure for a Shadowsocks node. 192.0.2.10 is a documentation-only address, and example-only-not-a-secret is a sample password. This snippet cannot be used to make a real proxy connection. Get the actual server, port, encryption method, and password from your service provider; don't guess them.

proxies:
  - name: "Demo Node"
    type: ss
    server: 192.0.2.10
    port: 443
    cipher: aes-128-gcm
    password: "example-only-not-a-secret"
    udp: true

proxy-groups:
  - name: "Manual Selection"
    type: select
    proxies:
      - "Demo Node"
      - DIRECT

select and url-test are not the same

select lets you choose a member manually. url-test tests candidate members using the configured probe URL and interval. The results mainly reflect connectivity to that probe target; they don't measure download bandwidth or guarantee the best route for every website.

DIRECT is a built-in direct connection and does not need a separate entry in proxies. Setting udp: true on a node only enables the relevant UDP capability; the server, protocol, and local traffic interception method must also support it.

5. rule-providers: move rules into a separate file

rule-providers defines the source, format, and behavior of a rule set, but the declaration alone doesn't activate it. You also need to reference the rule set by name with RULE-SET in rules and specify the outbound for matches.

This example uses a local file so a demo URL won't be mistaken for a working rule source. First, create rules/local-direct.yaml in a directory permitted by the core, then load the main config. Relative paths are resolved against the core's working directory and path restrictions, not the browser or this article's location.

rule-providers:
  local-direct:
    type: file
    behavior: domain
    format: yaml
    path: ./rules/local-direct.yaml

The rule file can contain:

payload:
  - "example.com"
  - "+.example.org"

example.com demonstrates a single domain; +.example.org demonstrates a domain and its subdomains. These are documentation examples, not a recommended list of domains to route.

  • behavior: domain: the rule content should contain domain match entries, not complete DOMAIN-SUFFIX,... rules.
  • behavior: ipcidr: the rule content should contain IP ranges, such as 192.0.2.0/24.
  • behavior: classical: classic rule expressions such as DOMAIN-SUFFIX are supported. Entries in the rule set typically don't include an outbound; specify it where the set is referenced.

If you switch to type: http, provide a reachable url and set a cache path. For example, interval: 86400 sets the refresh interval to 86,400 seconds, or 24 hours. A failed download, an invalid file format, and a rule set that isn't referenced are different issues. Check the logs, file contents, and main config separately.

6. rules: match in order and set a fallback outbound

In Rule mode, rules are checked in list order, and generally the first matching rule determines the outbound. Put specific exceptions first, broader rules later, and MATCH last. The core doesn't wait for every rule to match and then pick the “best” one.

rules:
  - DOMAIN,example.com,DIRECT
  - DOMAIN-SUFFIX,example.net,Manual Selection
  - RULE-SET,local-direct,DIRECT
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - MATCH,Manual Selection

This section depends on the Manual Selection policy group and local-direct rule set defined earlier; it can't be imported as a complete config on its own. DOMAIN matches a specific domain, while DOMAIN-SUFFIX matches that domain and its subdomains. Don't treat them as interchangeable just because their names look similar.

no-resolve doesn't disable all DNS

IP-based rules may trigger resolution to match requests made with a domain name. In this example, no-resolve means not to initiate a DNS lookup solely for this rule. Requests that already use an IP address, or already have a usable resolution result, can still match. It doesn't disable the DNS module or guarantee that the request won't be resolved elsewhere in the process.

Putting MATCH first prevents later rules from being checked

If the first rule is MATCH,DIRECT, domain-based proxy rules below it will never match. When troubleshooting rules that don't seem to work, check the new connection's rule and outbound on the client's Connections page, then look for a broader rule above it. Test with a new connection after making changes; existing long-lived connections won't switch routes automatically.

7. YAML indentation errors: check parsing and runtime behavior separately

Use two spaces per indentation level and avoid tabs. YAML uses indentation to define structure; a space is usually required after a colon, and list items start with a hyphen followed by a space. The line number in an error may point to where the parser detected the problem, even if the actual issue is on the preceding line.

Error 1: a field is indented at the parent level

Here, enable is not nested under dns. The YAML may still be valid, but its structure isn't what the core expects.

# Incorrect: enable is a top-level field
dns:
enable: true

# Correct
dns:
  enable: true

Error 2: list items are not nested under their field

# Incorrect: DIRECT is at the same level as proxies
proxy-groups:
  - name: "Manual Selection"
    type: select
    proxies:
    DIRECT

# Correct
proxy-groups:
  - name: "Manual Selection"
    type: select
    proxies:
      - DIRECT

Error 3: special characters and duplicate keys change the content

Quote passwords or names containing : or a space followed by #. For example, name: "Route: A #1" clearly preserves the entire string. Don't define two dns: or two rules: keys at the same level and expect them to merge automatically. The parser may report an error or keep only one value; neither is a reliable way to override settings.

“Policy group not found” and “rule set not found” are usually reference errors, not indentation errors. Check node, policy group, and rule set names character by character instead of repeatedly adjusting spaces around the reported line.

8. Verify the applied config: check the inbound, DNS, outbound, and rules

Don't combine all the snippets above into a production config. Each one illustrates a different part of the structure; the node uses a documentation-only address, and the rule set requires a local file to be created first. Make changes to a working subscription config, changing one target field at a time.

  1. Keep a baseline. Back up the current config and note the mixed port, operating mode, and selected policy group member. Confirm that the Config page has the profile you just edited enabled.
  2. Check that the config loaded. After applying your changes, open the Logs page and fix any parsing or name-reference errors first. Don't use connection results to judge new rules until the config has loaded successfully.
  3. Verify the inbound. Confirm that the actual listening port is 7897 or the value you changed it to. If an app isn't using the system proxy, determine whether it needs a manual proxy setting or TUN interception.
  4. Check DNS resolution. Distinguish between DNS timeouts, failed resolution of a proxy hostname, and failed resolution of the destination hostname. With fake-ip enabled, a mapped address alone is not evidence of a failure.
  5. Verify the outbound. On the Proxies page, check which member the policy group actually selected. Then open the Connections page to see the rule matched by a new request and its outbound route.
  6. Check that changes persist. Update the subscription or reload the config once, then confirm that your custom changes are still there. If they were overwritten, move them to an appropriate override mechanism.

For a closer look at how the fields fit together, continue with Advanced Config. If mixed ports, policy groups, and TUN are unfamiliar, start with the Glossary. Confirm that requests reach the client before checking DNS and rules; this makes issues easier to isolate than replacing the entire YAML file at once.

Download Clash