First, know what each page is for. The tutorial page is the fast-track path: install the client, import a subscription, pick a mode, and verify connectivity — just follow along and it works. This page is a reference handbook — it doesn't walk through steps, it explains what each field in config.yaml means, what values it accepts, and how to write it. Most subscription configs already ship pre-written; the handbook's job is to help you read and correctly edit them. The clients covered here match the lineup on the download page: Clash Plus is the top pick on every platform, and along with Clash Verge Rev and FlClash, they all share the mihomo core ecosystem — this handbook applies equally to all of them.
01YAML Structure Overview
config.yaml is the core's sole input. GUI clients like Clash Verge Rev, Clash Plus, and FlClash all do fundamentally the same thing: manage this file and hand it off to the mihomo core to execute. Every click in the UI — switching a node, changing a mode, adjusting a port — ultimately rewrites this YAML text. Understand this file and you understand everything a client does; edit it correctly and every client behaves correctly.
You don't need to memorize file paths. In Clash Verge Rev's config page, right-click any subscription card and choose "Open File" to jump straight to the raw config; the same menu also has update and edit options. For headless setups (servers, routers) with no GUI, the file location comes from startup flags — -f for a specific file or -d for a directory — independent of any client.
The top-level structure splits into five sections by responsibility. Order isn't enforced, but the community convention is fixed as follows:
# ① General fields: ports, mode, logging, external control
mixed-port: 7897
mode: rule
log-level: info
# ② DNS: the core handles domain resolution
dns:
enable: true
# ③ Proxies: the outbound node list
proxies: []
# ④ Proxy groups: how nodes are organized
proxy-groups: []
# ⑤ Rules: routing logic, evaluated top to bottom
rules:
- MATCH,DIRECT
Beyond these five sections is an extension zone: proxy-providers aggregates subscription nodes, rule-providers pulls in external rule sets, tun takes over system traffic, hosts defines a static domain table, and listeners adds extra listening ports. Look up whichever you need in its dedicated section.
Six hard rules of YAML syntax — break any one and activation fails:
- Use spaces for indentation only, never tabs; indentation at the same level must be consistent width, conventionally two spaces.
key: valuerequires a space after the colon —key:valueis invalid syntax.- List items start with
-, also followed by a space; the-can align with the parent key or be indented further — just stay consistent throughout the file. - Quote a string if it contains
#or:, starts with@,&, or*, or looks like a number or boolean. Password fields almost always need quoting. #starts a comment; leave a space between it and the preceding content, or the#gets swallowed into the string before it.- Anchors
&nameand references*namecan reuse repeated blocks — the core parses standard YAML and supports this feature.
A minimal working config. In twenty lines, this already delivers full routing: local mixed port + a single node + direct connection for domestic traffic, proxy for everything else:
mixed-port: 7897
allow-lan: false
mode: rule
log-level: info
dns:
enable: true
nameserver:
- 223.5.5.5
- 119.29.29.29
proxies:
- name: NodeA
type: ss
server: ss.example.com
port: 8388
cipher: aes-128-gcm
password: "your-password"
proxy-groups:
- name: Default Proxy
type: select
proxies:
- NodeA
- DIRECT
rules:
- GEOSITE,cn,DIRECT
- GEOIP,CN,DIRECT,no-resolve
- MATCH,Default Proxy
Changes take two steps: edit the file, then have the core reload it. In Clash Verge Rev, re-activating the config triggers a hot reload; GUI settings like system proxy, TUN, and launch-on-startup are client-side settings, not part of the subscription file — don't conflate the two.
Watch out for core differences. The original Clash is no longer maintained; Clash Meta was renamed mihomo and continues development — fields aren't shared across the three core generations. Node types and logic rules added by mihomo (vless, hysteria2, tuic, wireguard) aren't recognized by older cores. See the blog post "Clash Core Versions Explained" for which core each client bundles. This page's field reference follows mihomo throughout.
02General Fields: Ports, Mode & Baseline Behavior
General fields sit at the top level and control the core's listening ports, mode, and baseline behavior. They're not tied to any specific node — changing any of them affects the whole setup. Subscription configs usually ship with sane defaults; the ones you'll actually touch are ports, mode, and logging.
The port family. port is the HTTP proxy port, socks-port is the SOCKS5 port, and mixed-port merges both protocols onto one port — since system proxy settings and most apps only recognize one type, a mixed port skips the either-or dilemma; Clash Verge Rev defaults to mixed port 7897. redir-port and tproxy-port are for Linux transparent proxying only — leave them blank on desktop.
LAN access. allow-lan: true opens up LAN access, bind-address picks which network interface to listen on, and * means all interfaces. For the full setup letting phones and TVs share your computer's proxy, see the blog post "Setting Up Mixed Port & LAN Sharing". Opening it up means exposing it — only enable this on networks you trust, and keep it false on public Wi-Fi.
Mode. mode has three options: rule routes traffic by rule (the everyday default), global sends everything through one selected proxy group, and direct sends everything unproxied. Switching modes in the GUI just rewrites this field. The standard two-step debug for rules: switch to global first to confirm the proxy chain itself works, then switch back to rule and check rules one by one.
Logging and external control. log-level has five tiers, from silent to debug — use info day-to-day, bump to debug temporarily while troubleshooting, then dial it back down; debug logs are large and include every domain visited. external-controller is the listening address for the core's RESTful API — the GUI and any third-party dashboard control the core through it; if you bind it to a non-loopback address, you must also set secret, or you're effectively handing proxy control to anyone on the same network.
Fine-tuning. unified-delay: true normalizes latency measurement, canceling out protocol handshake differences so node latencies are actually comparable. tcp-concurrent: true dials candidate addresses concurrently and keeps the fastest. find-process-mode controls process matching, which PROCESS-NAME rules depend on. profile.store-selected: true makes the core remember manually selected nodes across restarts. ipv6: false is a common fix for "connects but won't load" symptoms on networks with broken IPv6.
| Field | Typical value | Description |
|---|---|---|
| port | 7890 | HTTP proxy port |
| socks-port | 7891 | SOCKS5 proxy port |
| mixed-port | 7897 | Mixed port for HTTP and SOCKS, recommended |
| redir-port / tproxy-port | 7892 / 7893 | Linux transparent proxy only, leave blank on desktop |
| allow-lan | false | Whether to allow LAN devices to connect |
| bind-address | * | Listening address when allow-lan is enabled |
| mode | rule | One of rule / global / direct |
| log-level | info | silent / error / warning / info / debug |
| ipv6 | false | Whether to allow AAAA resolution and IPv6 outbound |
| external-controller | 127.0.0.1:9090 | Core API listening address |
| secret | empty | API access key, required for non-loopback listening |
| profile.store-selected | true | Remembers manually selected nodes |
port: 7890
socks-port: 7891
mixed-port: 7897
allow-lan: false
bind-address: "*"
mode: rule
log-level: info
ipv6: false
unified-delay: true
tcp-concurrent: true
find-process-mode: strict
external-controller: 127.0.0.1:9090
secret: "your-secret"
profile:
store-selected: true
store-fake-ip: false
bind: address already in use error on activation means the port is taken: switch mixed-port, or find and stop the process using it. On Windows, locate it with netstat -ano | findstr :7897; on macOS and Linux, use lsof -i :7897.
03DNS Fields: Resolution Path & fake-ip
DNS gets its own chapter because routing accuracy depends on it more than anything else. Rules like GEOIP and IP-CIDR both need a resolved result first; if resolution is tampered with, routing follows it into the wrong path. dns.enable: true is the prerequisite — set it to false and this whole section is inert, the core falls back to system resolution, and fake IPs and policy-based resolution both stop working.
Listening and mode. listen sets the address the core's DNS service listens on; in TUN mode, queries are intercepted internally by the core, so nothing needs to change on the system side. enhanced-mode: fake-ip is the mainstream choice: domain lookups immediately return a fake address from the 198.18.0.1/16 pool, and once the connection is actually established, the core matches rules by domain — skipping the wait for a real resolution and noticeably speeding up page loads. The old redir-host mode has been removed from mihomo; delete it if you see it in an older config.
fake-ip boundaries. fake-ip-range defaults to 198.18.0.1/16 — only change it if it conflicts with an internal subnet. fake-ip-filter is a whitelist of domains that never get a fake address: LAN domains, NTP time servers, and system connectivity checks must be listed, or printers, router admin panels, and time sync will mysteriously fail. The example below covers the common entries — copy it, then add your own internal domains.
Resolver groups. nameserver is the default group, supporting multiple formats (see table below); multiple servers are queried concurrently and the fastest reply wins. proxy-server-nameserver resolves proxy node domains specifically — since a node's address is itself often a domain, use this to specify a trusted resolver, avoiding the deadlock of "needing the proxy to resolve the proxy." direct-nameserver serves directly connected domains, typically your ISP's or a domestic public DNS.
| Format | Protocol | Description |
|---|---|---|
| 223.5.5.5 | UDP 53 | Plaintext query, fastest, can be intercepted |
| tls://dns.alidns.com | DoT | TLS-encrypted channel |
| https://doh.pub/dns-query | DoH | HTTPS encryption, can run over port 443 |
| quic://dns.alidns.com | DoQ | QUIC transport, low latency |
| dhcp://en0 | DHCP | Uses the DNS handed out by DHCP on the network interface |
Policy-based resolution. nameserver-policy routes queries to a resolver by domain — the key can be a specific domain, a geosite: category, or a rule-set: rule set. This is how you send domestic domains through an ISP DoH server and everything else through a trusted overseas DoH server. The old fallback field is deprecated and replaced by nameserver-policy in mihomo; when migrating, rewrite it as "which resolver group serves which domain category."
Other switches. respect-rules: true makes even overseas resolvers route their own traffic by rule, and needs to be paired with proxy-server-nameserver. use-hosts and use-system-hosts control where the hosts table comes from. prefer-h3 prioritizes HTTP/3 for DoH queries.
dns:
enable: true
listen: 0.0.0.0:53
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
- "time.*.com"
- "ntp.*.com"
- "+.msftconnecttest.com"
- "+.msftncsi.com"
use-hosts: true
use-system-hosts: true
prefer-h3: true
nameserver:
- https://doh.pub/dns-query
- https://dns.alidns.com/dns-query
proxy-server-nameserver:
- https://doh.pub/dns-query
direct-nameserver:
- 223.5.5.5
- 119.29.29.29
nameserver-policy:
"geosite:cn":
- 223.5.5.5
- https://doh.pub/dns-query
"geosite:geolocation-!cn":
- https://dns.cloudflare.com/dns-query
- https://dns.google/dns-query
Debugging clues. If a page "connects but won't load," loads painfully slowly, or resolves to the wrong region, check DNS first: look up the domain in the logs to see which resolver group it went through and what result it got, then go back and fix the corresponding field.
04Proxy Fields: the proxies Array
proxies is an array — one element per node. Every node shares four base fields: name, type, server, port; everything else depends on type. Misspell a type-specific field and the core won't error out — it just ignores it, and the node shows up as unreachable.
name is the node's identity: proxy groups reference it by name, a duplicate name has the later one override the earlier one, and renaming it breaks every reference. Quote the name if it contains spaces, colons, or #. server can be a domain or an IP; when it's a domain, proxy-server-nameserver handles the resolution, as covered in the previous chapter.
Common optional fields. udp: true enables UDP forwarding, needed for QUIC, gaming, and voice calls. skip-cert-verify: true skips certificate validation — use it only as a temporary troubleshooting step. tfo enables TCP Fast Open. interface-name specifies the outbound network interface, useful on multi-NIC machines.
Shadowsocks
- name: ss-node
type: ss
server: ss.example.com
port: 8388
cipher: aes-128-gcm
password: "your-password"
udp: true
cipher common values: aes-128-gcm, aes-256-gcm, chacha20-ietf-poly1305, 2022-blake3-aes-128-gcm. plugin can load obfs or v2ray-plugin for traffic obfuscation, with parameters under plugin-opts.
VMess
- name: vmess-ws
type: vmess
server: vmess.example.com
port: 443
uuid: 00000000-0000-0000-0000-000000000000
alterId: 0
cipher: auto
tls: true
servername: vmess.example.com
network: ws
ws-opts:
path: /ray
headers:
Host: vmess.example.com
udp: true
alterId should always be 0 on modern servers. network supports tcp, ws, grpc, h2, http; for ws transport, the path and headers.Host under ws-opts must exactly match the server side — a single mismatched character means a 400 error.
VLESS + Reality
- name: vless-reality
type: vless
server: 192.0.2.10
port: 443
uuid: 00000000-0000-0000-0000-000000000000
network: tcp
tls: true
udp: true
flow: xtls-rprx-vision
servername: www.microsoft.com
client-fingerprint: chrome
reality-opts:
public-key: "your-public-key"
short-id: "0123456789abcdef"
flow only recognizes xtls-rprx-vision. Reality's public-key and short-id come from the server config; client-fingerprint should generally be chrome, and servername is the domain the server is disguising as.
Trojan
- name: trojan-node
type: trojan
server: trojan.example.com
port: 443
password: "your-password"
sni: trojan.example.com
alpn:
- h2
- http/1.1
skip-cert-verify: false
udp: true
sni must match the server certificate's domain, and alpn is typically h2 or http/1.1. The password is a credential — leaking it leaks the node.
Hysteria2
- name: hy2-node
type: hysteria2
server: hy2.example.com
port: 443
password: "your-password"
obfs: salamander
obfs-password: "obfs-password"
sni: hy2.example.com
skip-cert-verify: false
up: 50
down: 200
Built on QUIC, always UDP, so the udp field doesn't need to be set. obfs currently only supports salamander, with the password under obfs-password. up and down are in Mbps — overstating bandwidth backfires on congestion control, so fill in real values. On heavily throttled networks, ports enables port hopping.
TUIC
- name: tuic-node
type: tuic
server: tuic.example.com
port: 443
uuid: 00000000-0000-0000-0000-000000000000
password: "your-password"
alpn:
- h3
congestion-controller: bbr
udp-relay-mode: native
reduce-rtt: true
sni: tuic.example.com
The fifth-generation protocol. congestion-controller accepts bbr, cubic, or new_reno — bbr tends to be more stable on lossy links. udp-relay-mode defaults to native; reduce-rtt: true reduces handshake latency.
WireGuard
- name: wg-node
type: wireguard
server: 198.51.100.20
port: 51820
ip: 172.16.0.2
private-key: "your-private-key"
public-key: "peer-public-key"
mtu: 1420
udp: true
ip is the assigned tunnel address; private-key is your own key and public-key is the peer's — don't swap them. mtu is commonly 1420; some providers require three reserved byte values, which you should copy directly from the official client's export.
Subscription Aggregation: proxy-providers
Nodes delivered via subscription are managed by proxy-providers: the core periodically fetches updates and runs health checks, and proxy groups reference the whole set with use. Hand-written nodes and provider nodes can coexist in the same config.
proxy-providers:
provider-01:
type: http
url: "https://example.com/subscribe?token=xxxx"
path: ./providers/provider-01.yaml
interval: 86400
health-check:
enable: true
url: http://www.gstatic.com/generate_204
interval: 300
How to check fields: when a node won't connect, find its type's example section and compare field by field — extra fields are ignored, missing fields fall back to defaults, and typos raise no warning. Subscription nodes' fields follow what the provider sends; core field names are consistent everywhere.
05Proxy Group Fields: proxy-groups
Proxy groups decide who traffic gets handed to. Rules only reference a policy name; behind that name is a group, and inside the group are nodes — this three-layer separation means you can swap nodes without touching rules, and edit rules without touching nodes.
Five types, each behaving differently:
| type | Behavior | Use case |
|---|---|---|
| select | Manual selection | Outermost entry group, GUI uses whatever you click |
| url-test | Periodic latency test, picks the lowest | Auto-picks the best among nodes in the same region |
| fallback | Takes the first available in order | Primary/backup failover, auto-reverts when primary recovers |
| load-balance | Spreads connections across multiple nodes | Heavy downloads, multi-link aggregation |
| relay | Chained links | Relay acceleration, special exit nodes |
- select: manual selection, ideal as the outermost entry group with other groups nested underneath it.
- url-test: periodically tests latency across nodes in the group and picks the lowest; set
toleranceto 50 (ms) to stop latency jitter from causing constant node flapping. - fallback: takes the first node in proxies order that passes the health check; automatically reverts once the primary node recovers.
- load-balance:
strategyhas three options — consistent-hashing pins the same domain to the same node, keeping site sessions stable; round-robin cycles through nodes; sticky-sessions keeps the same session on the same node. - relay: traffic enters through the first node and exits through the last, with every hop in between required to be working — if any hop fails, the whole chain breaks.
Common fields. proxies lists node names, use lists proxy-providers names, and the two can be mixed. filter uses a regex to match node names (e.g. Hong Kong|HK), exclude-filter excludes by the same logic in reverse, and exclude-type excludes by protocol type. icon supplies a GUI icon, hidden: true hides the group in the GUI, and disable-udp: true blocks the group from forwarding UDP.
Health check fields. url defaults to http://www.gstatic.com/generate_204, and a 204 response marks it healthy; interval is in seconds — too short drains battery, too long feels sluggish, with 300 being a common middle ground; timeout is the per-test timeout; lazy: true (the default) skips testing a group nobody's using; max-failed-times sets how many consecutive failures mark a node unhealthy; expected-status sets the expected HTTP status code.
Nesting. A group's proxies list can itself contain other group names — that's how a three-tier structure like "Default Proxy → Auto Select → individual nodes" gets built; rules only need to reference the outermost group name. Subscription configs usually already ship with several layers of groups — when adding nodes manually, add them to the outermost group so the change applies everywhere.
proxy-groups:
- name: Default Proxy
type: select
proxies:
- Auto Select
- Failover
- DIRECT
use:
- provider-01
- name: Auto Select
type: url-test
use:
- provider-01
url: http://www.gstatic.com/generate_204
interval: 300
tolerance: 50
lazy: true
- name: Failover
type: fallback
proxies:
- Hong Kong Node
- Japan Node
url: http://www.gstatic.com/generate_204
interval: 120
- name: Load Balance
type: load-balance
use:
- provider-01
strategy: consistent-hashing
url: http://www.gstatic.com/generate_204
interval: 300
- name: Relay Chain
type: relay
proxies:
- Entry Node
- Exit Node
For the finer details of when to use each auto-managed type — latency-based selection, failover, or load balancing — see the blog post "Which Clash Proxy Group Type Should You Use". There's one design principle for groups: keep them lean, since every extra group is another thing to maintain; group names get referenced by rules, so renaming one means updating the rules too.
06Rule Syntax: Top to Bottom, First Match Wins
Rules are the brains of routing, and the matching model boils down to one sentence: top to bottom, stop at the first match. Order is priority; MATCH matches unconditionally and must be the last rule — anything after it never runs.
A single rule has three parts: type,parameter,policy, with some types accepting a fourth part, no-resolve. The policy can be a proxy group name or a built-in policy: DIRECT connects directly, REJECT rejects and returns an error, REJECT-DROP silently drops the connection, and PASS skips the current branch and keeps matching (mainly used with SUB-RULES).
| Type | Parameter | Description |
|---|---|---|
| DOMAIN | Full domain | Exact match on a single domain |
| DOMAIN-SUFFIX | Domain suffix | Matches the domain and all its subdomains |
| DOMAIN-KEYWORD | Keyword | Matches if the domain contains it — use sparingly, high false-positive risk |
| GEOSITE | Category name | Domain category database, e.g. cn, category-games@cn |
| IP-CIDR / IP-CIDR6 | Subnet | Matches by destination IP |
| IP-ASN | ASN number | Matches by destination autonomous system |
| GEOIP | Country code | Matches by destination IP's country |
| SRC-IP-CIDR | Subnet | Matches by source IP |
| SRC-PORT / DST-PORT | Port | Matches by source / destination port |
| PROCESS-NAME | Process name | Matches by the initiating process |
| PROCESS-PATH | Full path | Matches by process path |
| RULE-SET | Rule set name | References rule-providers |
| AND / OR / NOT | Sub-rule | Logical combination, mihomo-specific |
| SUB-RULES | Sub-rule group name | Enters a sub-rule branch |
| MATCH | none | Catch-all, must be the last rule |
Domain-based and IP-based rules are a dividing line. Domain rules (DOMAIN, DOMAIN-SUFFIX, DOMAIN-KEYWORD, GEOSITE) match directly against the connection's domain — no resolution needed. IP-based rules (IP-CIDR, GEOIP, IP-ASN) need the destination IP — when a domain-based connection reaches an IP rule, the core is forced to resolve it first just to evaluate the rule. The fourth part, no-resolve, blocks that resolution: domain connections skip the rule entirely, and only connections that are already pure IP get matched against it. Every IP-based rule should carry no-resolve unless you specifically want routing to depend on the resolved result.
GEO data. GEOSITE and GEOIP depend on the geosite.dat and geoip.dat (or mmdb) data files; geodata-mode: true switches to the dat format. These files update alongside the core, and if missing, the corresponding rules silently fail to match, showing up as broken routing.
Logical Rules
mihomo supports combining sub-rules with AND, OR, and NOT, wrapped in double parentheses:
rules:
- AND,((DOMAIN-SUFFIX,example.com),(PROCESS-NAME,chrome.exe)),Default Proxy
- OR,((DOMAIN-KEYWORD,blog),(DOMAIN-SUFFIX,notes.io)),Default Proxy
- NOT,((GEOSITE,cn)),Default Proxy
Rule Sets: rule-providers
Large, frequently updated rules are handed off to rule-providers as external rule sets, referenced in rules with RULE-SET,name,policy; behavior has three options: domain (domain suffix), ipcidr (IP range), classical (the classic three-part format).
rule-providers:
ad-list:
type: http
behavior: domain
format: yaml
url: "https://example.com/rules/ad-list.yaml"
path: ./ruleset/ad-list.yaml
interval: 86400
rules:
- RULE-SET,ad-list,REJECT
- MATCH,Default Proxy
Process matching. PROCESS-NAME and PROCESS-PATH depend on find-process-mode; on Windows, process names include the .exe extension, while macOS and Linux use the executable's file name.
Ordering principles:
- Specific before broad: DOMAIN before DOMAIN-SUFFIX, suffix rules before GEOSITE.
- Put LAN and internal subnets at the top, routed directly, never through a proxy.
- Wrap up domestic direct-connect rules with GEOSITE,cn plus GEOIP,CN — don't list domains one by one.
- MATCH always comes last, pointing to the main proxy group or DIRECT.
rules:
# LAN and internal subnets, direct connect
- DOMAIN-SUFFIX,local,DIRECT
- 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
# Processes and apps
- PROCESS-NAME,steam.exe,Game Boost
# Domain rules, specific first
- DOMAIN,api.example.com,Default Proxy
- DOMAIN-KEYWORD,telegram,Default Proxy
# Wrap up with category databases
- GEOSITE,category-games@cn,DIRECT
- GEOSITE,cn,DIRECT
- GEOIP,CN,DIRECT,no-resolve
# Catch-all
- MATCH,Default Proxy
07Override & Merge: Keep Your Changes Across Subscription Updates
Manually editing a subscription file has a catch: the moment the subscription updates, every change gets wiped out. Clash Verge Rev solves this with a three-layer editing system, split by "what you're changing and whether it should stick around."
Layer one: edit file. Right-click a subscription card on the config page and choose "Edit File" to modify the raw YAML directly — changes take effect on save, but get overwritten on the next subscription update. Use this only for quick debugging or testing an idea; once verified, move the change to one of the two layers below.
Layer two: subscription-level editing. Right-click and choose "Edit Rules," "Edit Proxies," or "Edit Proxy Groups" to prepend or append changes to that subscription's rules, nodes, or groups respectively. It's tied to the current subscription and survives updates — this is the layer you'll use most: adding a LAN direct-connect rule or a self-hosted node both happen here.
Layer three: global extension config. Accessed from the top right of the config page, in two forms: Merge declares merge intent in YAML, while Script gets full access to the config object via JavaScript to rewrite it freely. It applies to every config and survives switching subscriptions — good for personal baseline settings unrelated to any particular subscription.
Merge: Declarative Merging
Six dedicated keys control array merge direction — prepend goes first, append goes last; prepending a rule means it takes priority over the subscription's own rules. Every other top-level key simply overrides the original value: scalars like mixed-port and mode are replaced as-is; nested sections like dns are replaced wholesale — when overriding, write out the entire section, not just half of it.
prepend-rules:
- DOMAIN-SUFFIX,internal.example.com,DIRECT
append-rules:
- DOMAIN-KEYWORD,download,Download Group
prepend-proxies:
- name: Self-Hosted Backup
type: ss
server: 203.0.113.10
port: 8388
cipher: aes-256-gcm
password: "your-password"
append-proxy-groups:
- name: Download Group
type: select
proxies:
- Self-Hosted Backup
- DIRECT
mixed-port: 7897
Script: Programmatic Rewriting
Use a script when you need conditional logic. The entry point is fixed as main(config), where the parameter is the fully merged config, and the return value becomes the final config handed to the core:
function main(config) {
config["mixed-port"] = 7897;
const extra = {
name: "Self-Hosted Backup",
type: "ss",
server: "203.0.113.10",
port: 8388,
cipher: "aes-256-gcm",
password: "your-password"
};
config.proxies = config.proxies || [];
config.proxies.push(extra);
(config["proxy-groups"] || []).forEach(function (group) {
if (Array.isArray(group.proxies)) {
group.proxies.push("Self-Hosted Backup");
}
});
return config;
}
The order of precedence is fixed: subscription source → subscription-level edits (rules/proxies/proxy groups) → global Merge → global Script → core. Debug by working backward through the chain: first check what the final config looks like at runtime, then narrow down which layer introduced the problem.
Common override scenarios:
- Direct-connect internal domains: add a DOMAIN-SUFFIX rule via prepend-rules so it takes priority and matches first.
- Inject a self-hosted node into every group: use a Script to loop through proxy-groups and append it everywhere.
- Unify the port: write a single mixed-port line in Merge.
- Add internal domains to fake-ip-filter: override the entire dns section, copying the subscription's existing filter list in full before appending to it.
Other clients and headless setups. Clash Plus and FlClash both offer a similar "subscription + local edits" mechanism, with the same idea but a different entry point; running the core headless has no override layer at all — you edit the source file directly, so it's worth tracking history with Git. For a comparison of ways to keep the same config synced across multiple devices, see the blog post "Three Ways to Sync Clash Config Across Devices".
08Validation & Troubleshooting: From Errors to Logs
Read the error first when activation fails. When Clash Verge Rev activates a config, the core does a full parse and returns an error with a line number and a reason; go back to that line in the file, and nine times out of ten that's where the problem is. If the error message gets cut off, check the logs page for the full output.
Common YAML errors, ranked by frequency:
- Tab indentation: set your editor to convert tabs to spaces, and keep two spaces consistently throughout the file.
- Missing space after colon:
port:7890is invalid syntax. - Unquoted password containing
#: everything after the#gets treated as a comment, truncating the password. - Misaligned list indentation: the
-'s relationship to its parent key gets scrambled, and the node ends up under the wrong key. - Duplicate node names: the later one overrides the earlier one, leaving only one node for proxy groups to reference.
- A rule points to a policy name that doesn't exist: activation immediately errors with proxy not found — check the group name spelling.
Logs are your second line of defense. Temporarily bump log-level to debug, and the core's log page shows which rule each connection matched and which outbound it took; see the blog post "A Tour of the Clash Verge Rev Interface" for what each section of the UI does. Switch it back to info once you're done.
If a change "doesn't take effect," check in this order:
- You edited the file but never re-activated the config on the config page, so the core is still running the old one.
- You edited the subscription source, but the override layer changed it right back — check the final runtime config to confirm.
- The config is correct, but the GUI is still attached to the old core process — restart the core or reconnect.
- System proxy or TUN isn't enabled, so traffic never reaches the core in the first place — no config change will help.
Ports and LAN. A bind: address already in use error means the port is taken: switch mixed-port, or stop the process using it. If allow-lan is on but your phone can't connect: first check whether your computer's firewall allows the port, then confirm both devices are on the same subnet and you've entered the computer's internal IP.
fake-ip issues. Some apps (banking, government/enterprise, and some anti-cheat-enabled games) are sensitive to fake addresses: add the domain to fake-ip-filter, set up direct-nameserver, and if needed, route the whole rule direct. Re-activate the config after making changes for it to take effect.
TLS and time. For certificate errors, check your system clock first — even a few minutes of drift will break the handshake; skip-cert-verify is only a temporary troubleshooting step — turn it back to false once the connection is confirmed working.
DNS leaks and tampering. If you suspect a leak, check in order: whether all nameserver entries go through a trusted channel, whether proxy-server-nameserver is configured, whether respect-rules behaves as expected, and whether the geosite category names under nameserver-policy are spelled correctly — a misspelled category name fails silently with no error.
Wrapping up. Still stuck? Work through the categorized list on the FAQ page; client downloads and core details are on the download page, and a side-by-side comparison is on the client comparison page.