先确认内核,再读配置的引用关系
配置的核心是三层关系:节点定义出口,策略组组织出口,规则决定连接交给哪个出口。proxies 不是规则列表,proxy-groups 也不会自动让所有连接走代理。只有连接被客户端接管,并匹配到相应规则,配置里的选择才会生效。
Clash 是配置生态的常用称呼,但不同内核支持的字段并不完全相同。本文完整示例面向 mihomo,也就是原 Clash.Meta 内核;其中内联规则集等写法不能直接视为所有旧 Clash 内核都支持。先在客户端的「关于」或内核信息页确认内核名称,再对照配置文档。
proxies:保存单个节点的协议、服务器、端口和认证参数。proxy-groups:通过节点名或其他组名,把出口组织成可选择的策略。rule-providers:定义可复用的规则集,内容可以来自文件、HTTP 或内联列表。rules:按顺序匹配连接,并指定DIRECT、REJECT或策略组。
一份能加载的 config.yaml 结构示例
下面是一份完整的 mihomo 演示配置。它不包含远程代理节点,默认出口是 DIRECT,用途是观察配置加载、策略组选择和规则匹配,不能凭空提供代理线路。确认结构能加载后,再添加服务方提供的真实节点。
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false
dns:
enable: true
listen: 127.0.0.1:1053
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- 223.5.5.5
- 1.1.1.1
proxies: []
proxy-groups:
- name: "手动选择"
type: select
proxies:
- DIRECT
- REJECT
rule-providers:
local-demo:
type: inline
behavior: classical
payload:
- DOMAIN-SUFFIX,example.org
rules:
- DOMAIN,example.com,DIRECT
- RULE-SET,local-demo,DIRECT
- 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,手动选择
读取顺序与实际执行顺序不是一回事
顶层字段按「通用设置 → DNS → 节点 → 策略组 → 规则集 → 规则」排列,方便人工阅读;并不要求必须按这个顺序书写。真正对结果有直接影响的是 rules 列表中的先后顺序,以及策略组的初始选项。名称引用必须完全一致,包括空格、大小写和中文字符。
YAML 使用空格缩进,不要混入 Tab。本文每层使用 2 个空格,列表项用连字符加空格。包含特殊字符的名称或密码建议加引号;纯数字形式的密码也应按字符串填写,避免解析后类型发生变化。
通用字段:端口、运行模式与接管范围
| 字段 | 本例取值 | 实际作用 |
|---|---|---|
mixed-port | 7890 | 同一个监听端口接受 HTTP 和 SOCKS 代理连接。 |
allow-lan | false | 不开放给局域网设备使用,适合作为本机学习起点。 |
mode | rule | 按 rules 分流;全局模式不按这份规则逐条分配出口。 |
log-level | info | 记录常规运行信息,排查时可短暂切到 debug。 |
ipv6 | false | 本例关闭内核的 IPv6 支持,不等于关闭整个系统的 IPv6。 |
mixed-port: 7890 只表示内核准备在这个端口提供代理服务,不代表系统和所有应用已经使用它。普通应用可能遵循系统代理,也可能忽略系统代理;TUN 则通过虚拟网络接口接管更多流量,是否可用还取决于系统权限、路由与客户端实现。
本文没有启用 TUN,先把测试应用的 HTTP 代理设为 127.0.0.1:7890 即可验证入口。如果端口被其他程序占用,日志通常会出现 address already in use。此时要么关闭占用程序,要么同步修改配置与应用代理端口,例如都改成 7891。
dns:解析结果与规则匹配怎样配合
dns 段管理内核的域名解析。示例启用 fake-ip,使用 198.18.0.1/16 作为虚拟地址池;这些地址用于域名映射,不是网站真实服务器的地址。内核保留映射后,可以在后续连接中恢复域名,辅助域名规则匹配。
1053 是监听端口,不是上游 DNS 地址
listen: 127.0.0.1:1053 表示本机 DNS 服务入口,nameserver 中的两个 IP 才是上游解析器。本例使用普通 DNS,便于观察结构;选择上游时还要考虑当前网络的可达性和隐私需求,不能把某个公共 DNS 当成所有网络的固定答案。
- 仅开启
dns.enable,不会自动把系统所有 DNS 请求都送进内核。 - 系统 DNS 设置通常不能直接填写
127.0.0.1:1053这种带自定义端口的地址;接管方式需要客户端或本地转发配合。 - TUN 中的 DNS 劫持属于另一层配置。不要为了让 DNS 生效,就直接照抄其他系统的 TUN 参数。
- 应用自带的加密 DNS 可能改变域名解析路径。出现域名规则不命中时,应一并检查浏览器的安全 DNS 设置和实际连接记录。
本例没有加入 fake-ip-filter。如果某个局域网服务或应用不适合虚拟地址,可根据日志把具体域名加入过滤列表,再重建连接验证。不要直接加入范围过大的通配项,否则可能改变大量连接的解析行为。
proxies:节点参数必须与服务端一致
proxies: [] 表示节点列表为空。要添加节点,就把它替换成列表。下面仅演示 Shadowsocks 的字段结构:192.0.2.10 是文档示例地址,密码也是演示文本,不能用于实际联网。真实参数应从订阅或服务方后台获取,不要只替换服务器地址后保留其他字段。
proxies:
- name: "SS-示例"
type: ss
server: 192.0.2.10
port: 8388
cipher: aes-128-gcm
password: "demo-only-not-a-real-password"
udp: true
name 是后续策略组引用的标识;server 与 port 指向远端服务;cipher 和 password 必须与服务端匹配。这里的 8388 是远端端口,与本地 7890 不是同一个概念。
udp: true 表示允许该节点使用相应的 UDP 能力,不保证整个链路一定支持 UDP。服务端、协议、接管方式与目标网络都可能影响结果。其他协议也有各自字段,不能把 VMess、VLESS 或 Trojan 的参数硬塞进 type: ss 下。
节点名避免重复
建议采用能稳定识别的短名称,例如地区加用途,并保持唯一。订阅更新后如果名称发生变化,手写策略组里的旧名称可能失效;节点数量较多时,可进一步使用 proxy-providers 管理节点来源。注意它管理的是节点,不能和管理匹配条件的 rule-providers 混为一谈。
proxy-groups:把节点组合成规则可引用的策略
将真实节点加入 proxies 后,还需要把它放进策略组。下面的组通过名称引用上一节节点;只有换成有效节点参数后,选择该项才可能正常连接。
proxy-groups:
- name: "手动选择"
type: select
proxies:
- "SS-示例"
- DIRECT
select 是手动选择组。客户端一般会在「代理」或策略组页面显示它,点击其中一个成员即可选择出口。初次加载且没有历史选择时,通常使用列表第一项;如果开启了选择记录持久化,重新加载后可能恢复之前的选择,而不是回到第一项。
| 组类型 | 选择依据 | 使用注意 |
|---|---|---|
select | 用户手动指定成员 | 适合先验证节点,再固定使用某个出口。 |
url-test | 对测试 URL 的探测结果 | 测试延迟不等于所有网站的下载速度。 |
fallback | 按成员顺序选择可用项 | 更适合主备切换,不是始终选择最低延迟。 |
load-balance | 按配置策略分配连接 | 不会把单条下载连接的带宽简单叠加。 |
策略组还可以引用另一个策略组,但不能形成循环。比如「日常出口」引用「手动选择」可以,「日常出口」与「手动选择」再互相引用则应避免。遇到 proxy not found 一类错误,优先核对名称和引用对象是否确实存在。
rule-providers 与 rules:规则集定义和匹配顺序
完整示例中的 local-demo 是内联规则集,behavior: classical 表示内容使用带规则类型的写法。它包含 DOMAIN-SUFFIX,example.org,既匹配 example.org,也匹配它的子域名。规则集只保存匹配条件;最终走哪个出口,由 rules 中的 RULE-SET,local-demo,DIRECT 指定。
三种规则集行为不能随意混写
classical:条目包含规则类型,例如DOMAIN-SUFFIX,example.org。domain:条目是域名或受支持的域名匹配表达式,不应照搬 classical 的整行格式。ipcidr:条目为 IP 网段,例如192.168.0.0/16。
如果改用 type: http,还需要配置实际可访问的 url,并按所用格式设置缓存路径、更新间隔等字段。比如 interval: 86400 表示 86400 秒,也就是 24 小时。远程内容必须与声明的行为、格式相符;下载成功不等于内容一定能解析。
rules 自上而下,首次命中后结束
示例第一行精确匹配 example.com 并直连,第二行引用规则集,再处理几个本地网段,最后用 MATCH,手动选择 兜底。MATCH 会接住剩余连接,因此应放在最后;如果提前放到第一行,后面的规则就没有匹配机会。
rules:
- DOMAIN,example.com,DIRECT
- DOMAIN-SUFFIX,example.org,手动选择
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- MATCH,手动选择
DOMAIN 是精确域名匹配,DOMAIN-SUFFIX 是后缀匹配,二者不要混用。IP 规则后的 no-resolve 表示不要仅为了判断该条规则而主动解析域名;如果连接本身已有目标 IP,仍可据此匹配。它既不是禁用整个 DNS,也不是强制让这个网段直连的额外开关。
还要留意:把 GEOIP 或 GEOSITE 写入规则,会引入相应地理数据的依赖。本文最小示例特意没有使用这两类规则,避免第一次加载就受数据文件缺失或更新失败影响。
保存、校验与加载:按三步定位错误
第一步:用内核检查语法和引用
如果已经安装独立 mihomo,可在配置所在目录运行下面的命令。Windows PowerShell 中,当前目录里的程序通常写成 .\mihomo.exe;可执行文件实际名称以本机为准。
mihomo -t -f ./config.yaml
# Windows PowerShell
.\mihomo.exe -t -f .\config.yaml
检查通过只说明配置能被当前内核接受,不说明节点在线、密码正确或 DNS 可达。命令检查通过而客户端失败时,继续核对两者是否使用相同内核、相同文件,以及客户端是否叠加了其他设置。
第二步:加载后确认运行值
- 在客户端「配置」页导入本地 YAML,选中该配置;如果界面提供「编辑」入口,修改后保存并重新加载。
- 在「代理」页找到「手动选择」组,确认成员存在。尚未添加真实节点时,保持
DIRECT。 - 将运行模式设为「规则」,核对实际混合端口是否为
7890。不同客户端的菜单名称可能略有差别。 - 用明确经过代理入口的请求测试,再查看「连接」和「日志」页面,而不是只看浏览器是否能打开网页。
curl -I --proxy http://127.0.0.1:7890 https://example.com
# Windows 中使用 curl.exe,避免命令别名差异
curl.exe -I --proxy http://127.0.0.1:7890 https://example.com
这条请求按示例应匹配 DOMAIN,example.com,DIRECT。能否收到 HTTP 响应还取决于本地网络;判断规则是否正确,应优先看连接详情里的规则与最终出口。该命令验证的是 HTTP 代理入口,不是 TUN 或系统 DNS 接管情况。
第三步:按错误类型回查,不同时修改多处
| 现象 | 优先检查 | 下一步 |
|---|---|---|
| YAML 解析失败 | 缩进、Tab、冒号和引号 | 回到报错行及上一行,重新运行配置检查。 |
| 找不到节点或策略 | 组名、节点名是否完全一致 | 从定义处复制名称,避免手输差异。 |
| 监听端口失败 | 7890 或 1053 是否被占用 | 关闭冲突程序,或同步修改两端设置。 |
| 规则没有命中 | 是否为规则模式、连接是否经过内核 | 检查前置规则,并关闭旧连接后重试。 |
| 规则正确但连接超时 | 所选节点、认证参数和目标网络 | 固定单个节点测试,区分规则问题与线路问题。 |