Skip to content

Mihomo 的配置项很多,但真正困难的不是记住每个 YAML 字段,而是理解不同模块的职责边界。

如果把所有配置都看成“代理设置”,很容易出现下面几类问题:

  • override 中尝试过滤节点;
  • proxy-group 中配置测速,却忘记 Provider 节点由 Provider 自己维护健康状态;
  • 把节点来源、节点筛选、节点选择和流量路由混在一起;
  • TUN 已经接管流量,但 DNS 仍然从系统路径泄漏;
  • 规则写得很多,却没有形成稳定的匹配顺序。

理解 Mihomo,首先要建立一条完整的数据链路。

text
应用流量

入站:mixed-port / redir-port / tproxy-port / TUN / listeners

DNS 解析与域名嗅探

rules 路由匹配

proxy-groups 策略决策

proxies / proxy-providers 提供实际节点

网络出口

这条链路同时给出了配置模块之间的职责边界。

一、Mihomo 配置的核心分层

可以把主配置拆成八层。

层级主要配置核心职责
运行层modelog-levelipv6profile控制内核本身如何运行
入站层mixed-porttproxy-porttunlisteners决定流量如何进入内核
识别层dnshostssniffer将 IP、域名和连接信息关联起来
节点来源层proxiesproxy-providers定义实际可用的出站节点
策略层proxy-groups决定在多个节点之间如何选择
路由层rules决定一条流量进入哪个策略组
规则来源层rule-providerssub-rules管理大规模和可复用规则
管理层external-controllerexternal-ui提供 API、面板和运行时控制

最重要的四个概念是:

text
proxy-providers:节点从哪里来
proxy-groups:节点怎样被选择
rules:流量进入哪个策略组
rule-providers:规则从哪里来

这四者名称相似,但职责完全不同。

二、全局运行配置

一份常见的基础配置如下:

yaml
mode: rule
log-level: info
ipv6: false

allow-lan: true
bind-address: "*"

unified-delay: true
tcp-concurrent: true

profile:
  store-selected: true
  store-fake-ip: true

mode

常见值包括:

  • rule:按照 rules 进行分流;
  • global:所有流量进入 GLOBAL 策略;
  • direct:所有流量直接连接。

生产配置一般使用 rule

unified-delay

启用统一延迟计算方式,使不同协议节点的延迟结果更容易横向比较。

tcp-concurrent

当域名解析得到多个 IP 时,并发尝试建立 TCP 连接,使用更快成功的连接。它优化的是建连路径,不是简单地“多开几个连接”。

profile

yaml
profile:
  store-selected: true
  store-fake-ip: true
  • store-selected 保存策略组的上次选择;
  • store-fake-ip 保存 Fake-IP 映射,减少内核重启后映射全部失效的问题。

三、入站:流量如何进入 Mihomo

1. 普通代理端口

yaml
mixed-port: 7890

mixed-port 同时接受 HTTP 和 SOCKS5 代理,桌面环境中通常一个端口就够用。

其他常见端口包括:

yaml
port: 7890
socks-port: 7891
redir-port: 7892
tproxy-port: 7893
  • port:HTTP 代理;
  • socks-port:SOCKS 代理;
  • redir-port:透明接管 TCP;
  • tproxy-port:在 Linux 中透明接管 TCP 和 UDP。

2. TUN

TUN 创建虚拟网卡,将原本不支持系统代理的应用流量送入 Mihomo。

yaml
tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-redirect: true
  auto-detect-interface: true
  strict-route: true
  dns-hijack:
    - any:53
  mtu: 1500

这里需要区分三个动作:

  1. auto-route 把系统流量路由到 TUN;
  2. dns-hijack 把 DNS 请求交给 Mihomo;
  3. strict-route 收紧路由边界,减少绕过 TUN 的流量。

TUN 只是流量入口。它并不自动保证 DNS 路径正确,也不决定流量最终走哪个节点。

四、DNS:恢复域名语义

规则系统更擅长基于域名分流,但网络连接最终需要 IP。DNS 模块负责在域名、IP 和规则之间建立联系。

典型的 Fake-IP 配置如下:

yaml
dns:
  enable: true
  listen: 0.0.0.0:1053
  ipv6: false

  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16

  fake-ip-filter:
    - "*.lan"
    - "*.local"

  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29

  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query

  proxy-server-nameserver:
    - https://dns.alidns.com/dns-query

三组 DNS 的职责

default-nameserver

用于解析 DNS 服务器自身的域名。

例如配置中使用:

text
https://dns.alidns.com/dns-query

在请求这个 DoH 服务之前,内核必须先知道 dns.alidns.com 的 IP。这个启动阶段的解析由 default-nameserver 处理。

nameserver

用于解析普通业务域名,例如网页、API 和应用服务域名。

proxy-server-nameserver

专门解析代理节点的 server 域名。

它的重要性在于避免循环依赖:

text
连接代理节点
  → 需要先解析节点域名
  → 如果节点域名解析又必须经过该代理
  → 形成依赖环

将代理服务器域名解析单独隔离,可以让节点建立连接的前置路径更明确。

五、Sniffer:从连接中恢复域名

部分应用绕过系统 DNS,或者直接连接 IP。此时规则系统只能看到目标 IP,无法使用域名规则。

sniffer 可以从协议数据中提取域名:

  • HTTP Host;
  • TLS SNI;
  • QUIC 握手信息。
yaml
sniffer:
  enable: true
  force-dns-mapping: true
  parse-pure-ip: true
  override-destination: true

  sniff:
    HTTP:
      ports:
        - 80
        - 8080-8880
    TLS:
      ports:
        - 443
        - 8443
    QUIC:
      ports:
        - 443
        - 8443

Sniffer 的职责不是“解析所有加密流量”,而是在协议握手仍然暴露域名信息时恢复目标域名。

六、proxiesproxy-providers

静态节点:proxies

yaml
proxies:
  - name: 香港节点
    type: ss
    server: hk.example.com
    port: 443
    cipher: aes-128-gcm
    password: password
    udp: true

适合少量、稳定、由自己维护的节点。

动态节点:proxy-providers

yaml
proxy-providers:
  ss:
    type: http
    url: "https://example.com/subscription"
    path: ./proxy_providers/ss.yaml
    interval: 3600
    proxy: DIRECT

Provider 负责管理一批节点的生命周期:

text
下载或读取订阅

解析节点

覆写统一属性

过滤不需要的节点

执行健康检查

向 proxy-groups 提供节点

这比把订阅理解为“一个节点列表”更准确。

七、Proxy Provider 的四个处理阶段

1. 来源

yaml
proxy-providers:
  airport:
    type: http
    url: "https://example.com/subscription"
    path: ./proxy_providers/airport.yaml
    interval: 3600
    proxy: DIRECT
    size-limit: 10485760

常见类型:

  • http:远程下载;
  • file:读取本地文件;
  • inline:在主配置中直接写 payload

2. 统一覆写:override

yaml
override:
  udp: true
  tfo: true
  ip-version: ipv4-prefer
  additional-prefix: "[机场 A] "

override 用于修改节点属性,例如:

  • 是否启用 UDP;
  • 是否启用 TCP Fast Open;
  • IP 版本偏好;
  • 指定出口网卡;
  • 增加节点名前后缀;
  • 按正则表达式重命名节点。

例如:

yaml
override:
  proxy-name:
    - pattern: "IPLC-(.*?)倍"
      target: "IPLC x $1"

需要注意:override 的职责是修改节点,不是删除节点。

3. 节点过滤

只保留符合条件的节点:

yaml
filter: "(?i)(香港|HK|Hong[ _-]?Kong|🇭🇰)"

排除符合条件的节点:

yaml
exclude-filter: '(?i)(剩余流量|流量剩余|套餐流量|到期时间|过期时间|有效期|重置时间|官网|公告|remaining[ _-]*traffic|traffic[ _-]*left|expire[sd]?|expiry)'

按协议类型排除:

yaml
exclude-type: "ssr|http"

三者的差异是:

字段匹配对象结果
filter节点名称只保留匹配节点
exclude-filter节点名称删除匹配节点
exclude-type节点类型删除指定协议类型

因此,过滤“剩余流量”“到期时间”等伪节点应该写在 Provider 顶层:

yaml
proxy-providers:
  airport:
    type: http
    url: "https://example.com/subscription"

    override:
      udp: true
      tfo: true

    exclude-filter: '(?i)(剩余流量|到期时间|官网|公告)'

而不是写成:

yaml
proxy-providers:
  airport:
    override:
      exclude-filter: "剩余流量" # 错误的职责层级

4. 健康检查

yaml
health-check:
  enable: true
  url: https://www.gstatic.com/generate_204
  interval: 300
  timeout: 5000
  lazy: false
  expected-status: 204

这部分负责维护 Provider 内节点的可用性和延迟状态。

字段含义:

  • enable:启用健康检查;
  • url:测试目标;
  • interval:检查间隔,单位秒;
  • timeout:超时时间,单位毫秒;
  • lazy:未使用该 Provider 时是否停止主动测试;
  • expected-status:期望 HTTP 状态码。

八、(?i) 到底是什么

下面的过滤表达式:

yaml
filter: "(?i)(香港|HK|Hong Kong)"

(?i) 是正则表达式的忽略大小写标志,即 case-insensitive。

它能同时匹配:

text
HK
hk
Hong Kong
HONG KONG
hong kong

中文本身没有大小写,因此 (?i) 主要影响英文节点名。

下面的表达式:

regex
Hong[ _-]?Kong

其中 [ _-]? 表示中间允许出现零个或一个空格、下划线或连字符,因此可以匹配:

text
HongKong
Hong Kong
Hong_Kong
Hong-Kong

九、Proxy Group:对节点执行选择策略

Provider 解决“节点从哪里来”,代理组解决“节点怎样选”。

select

手动选择节点或其他策略组:

yaml
- name: 🚀 节点选择
  type: select
  proxies:
    - ⚡ 自动选择
    - 🇭🇰 香港自动
    - DIRECT

url-test

自动选择低延迟节点:

yaml
- name: 🇭🇰 香港自动
  type: url-test
  use:
    - ss
    - paofu
  filter: "(?i)(香港|HK|Hong[ _-]?Kong|🇭🇰)"
  tolerance: 50
  lazy: false

这里发生了三步处理:

  1. usesspaofu 两个 Provider 引入节点;
  2. filter 只留下香港节点;
  3. url-test 在这批候选节点中选择延迟更低的节点。

Provider 健康检查与代理组测试的边界

代理组中的:

yaml
url: https://www.gstatic.com/generate_204
interval: 300

只直接检查代理组 proxies 字段中引入的节点,不直接检查通过 use 引入的 Provider 节点。

因此,使用 use 时应该在每个 Provider 内配置 health-check

yaml
proxy-providers:
  ss:
    type: http
    url: "https://example.com/ss"
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 300
      lazy: false

  paofu:
    type: http
    url: "https://example.com/paofu"
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 300
      lazy: false

这个边界非常重要:

text
Provider 维护节点状态
Proxy Group 消费节点状态并执行选择策略

tolerance

yaml
tolerance: 50

表示新节点需要明显快于当前节点,超过一定延迟差后才切换。它用于减少延迟轻微波动导致的频繁跳节点。

  • tolerance: 0 更接近绝对最低延迟,但容易频繁切换;
  • tolerance: 3050 通常更稳定。

fallback

按顺序选择可用节点,当前节点失效后回退:

yaml
- name: 🛟 故障转移
  type: fallback
  use:
    - ss
    - paofu
  lazy: false

load-balance

把不同连接分配给多个节点:

yaml
- name: ⚖️ 负载均衡
  type: load-balance
  use:
    - ss
    - paofu
  strategy: consistent-hashing

负载均衡不是单连接带宽叠加,而是把不同连接分散到不同节点。

十、按照国家自动选择最低延迟节点

一份常用配置如下:

yaml
proxy-providers:
  ss:
    type: http
    url: "https://example.com/ss"
    path: ./proxy_providers/ss.yaml
    interval: 3600
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 300
      timeout: 5000
      lazy: false
    exclude-filter: '(?i)(剩余流量|到期时间|官网|公告)'

  paofu:
    type: http
    url: "https://example.com/paofu"
    path: ./proxy_providers/paofu.yaml
    interval: 3600
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 300
      timeout: 5000
      lazy: false
    exclude-filter: '(?i)(剩余流量|到期时间|官网|公告)'

proxy-groups:
  - name: 🇭🇰 香港自动
    type: url-test
    use:
      - ss
      - paofu
    filter: "(?i)(香港|HK|Hong[ _-]?Kong|🇭🇰)"
    tolerance: 50
    lazy: false

  - name: 🇯🇵 日本自动
    type: url-test
    use:
      - ss
      - paofu
    filter: "(?i)(日本|东京|大阪|JP|Japan|Tokyo|Osaka|🇯🇵)"
    tolerance: 50
    lazy: false

  - name: 🇸🇬 新加坡自动
    type: url-test
    use:
      - ss
      - paofu
    filter: "(?i)(新加坡|狮城|SG|Singapore|🇸🇬)"
    tolerance: 50
    lazy: false

  - name: 🚀 节点选择
    type: select
    proxies:
      - 🇭🇰 香港自动
      - 🇯🇵 日本自动
      - 🇸🇬 新加坡自动
      - DIRECT

这个结构实现了两级决策:

text
第一级:每个国家内部自动选择低延迟节点
第二级:手动或按业务选择国家策略组

相比把所有国家节点放进一个 url-test,这种方式更加稳定,也更容易针对不同业务制定规则。

十一、Rules:把业务流量交给策略组

规则基本格式为:

text
规则类型,匹配内容,目标策略

例如:

yaml
rules:
  - DOMAIN-SUFFIX,github.com,🚀 节点选择
  - DOMAIN-KEYWORD,youtube,🎬 视频
  - GEOSITE,cn,DIRECT
  - GEOIP,CN,DIRECT,no-resolve
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - MATCH,🐟 漏网之鱼

规则从上到下匹配,命中后通常不再继续匹配。因此规则顺序本身就是路由逻辑。

一般顺序可以组织为:

text
局域网和私有地址

需要强制直连的域名

特定业务规则

国内域名和国内 IP

代理规则

MATCH 兜底

MATCH 应该放在最后。

十二、Rule Provider:管理大型规则集

当规则数量变多时,不应全部堆进主配置。

yaml
rule-providers:
  private:
    type: http
    behavior: domain
    format: mrs
    url: "https://example.com/private.mrs"
    path: ./ruleset/private.mrs
    interval: 86400

在主规则中引用:

yaml
rules:
  - RULE-SET,private,DIRECT
  - MATCH,🚀 节点选择

常见 behavior

  • domain:域名集合;
  • ipcidr:IP 网段集合;
  • classical:完整规则行集合。

rule-providers 解决的是规则文件的下载、更新和解析,rules 仍然负责决定规则的匹配顺序和目标策略。

十三、完整配置骨架

下面这份配置不包含真实订阅地址,但展示了主要模块如何组合:

yaml
mode: rule
log-level: info
ipv6: false

allow-lan: true
bind-address: "*"
unified-delay: true
tcp-concurrent: true

profile:
  store-selected: true
  store-fake-ip: true

mixed-port: 7890

external-controller: 127.0.0.1:9090
secret: ""

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  strict-route: true
  dns-hijack:
    - any:53

dns:
  enable: true
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query
  proxy-server-nameserver:
    - https://dns.alidns.com/dns-query

sniffer:
  enable: true
  force-dns-mapping: true
  parse-pure-ip: true
  sniff:
    HTTP:
      ports: [80, 8080-8880]
    TLS:
      ports: [443, 8443]
    QUIC:
      ports: [443, 8443]

proxy-providers:
  airport:
    type: http
    url: "https://example.com/subscription"
    path: ./proxy_providers/airport.yaml
    interval: 3600
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 300
      timeout: 5000
      lazy: false
    override:
      udp: true
      tfo: true
    exclude-filter: '(?i)(剩余流量|到期时间|官网|公告)'

proxy-groups:
  - name: 🇭🇰 香港自动
    type: url-test
    use:
      - airport
    filter: "(?i)(香港|HK|Hong[ _-]?Kong|🇭🇰)"
    tolerance: 50
    lazy: false

  - name: 🚀 节点选择
    type: select
    proxies:
      - 🇭🇰 香港自动
      - DIRECT

rules:
  - GEOSITE,cn,DIRECT
  - GEOIP,CN,DIRECT,no-resolve
  - MATCH,🚀 节点选择

十四、常见配置错误

1. 在 override 中写 exclude-filter

错误原因:覆写和过滤是两个独立阶段。

yaml
override:
  exclude-filter: "剩余流量"

正确写法:

yaml
override:
  udp: true

exclude-filter: "剩余流量"

2. 把 use 当成节点名列表

use 引用的是 Provider 名称:

yaml
use:
  - ss
  - paofu

proxies 引用的是静态节点或其他代理组:

yaml
proxies:
  - 香港节点
  - 🇭🇰 香港自动
  - DIRECT

3. Provider 没有健康检查

如果代理组通过 use 引入 Provider,Provider 应该自己配置 health-check,否则自动选择缺乏持续更新的节点状态。

4. 国家关键词过于宽泛

例如只写:

yaml
filter: "港"

可能误匹配包含该字符的其他说明节点。更稳妥的写法是组合多个明确标记:

yaml
filter: "(?i)(香港|HK|Hong[ _-]?Kong|🇭🇰)"

5. exclude-filter 过于激进

直接排除:

yaml
exclude-filter: "流量"

可能误伤名称中包含“流量优化”等文字的正常节点。应该优先使用“剩余流量”“套餐流量”“到期时间”等完整语义。

6. 忽略空代理组

当某个 Provider 没有符合国家正则的节点时,国家策略组可能为空。生产配置需要确保:

  • Provider 节点命名稳定;
  • 正则覆盖机场实际命名;
  • 关键业务策略存在备用组或 DIRECT
  • 更新订阅后检查策略组是否仍有节点。

十五、最终心智模型

Mihomo 配置不应该被理解为一份巨大的 YAML,而应该被理解为多个阶段组成的处理管线:

text
入站负责接管流量
DNS 与 Sniffer 负责恢复目标语义
Rules 负责业务分类
Proxy Groups 负责策略决策
Proxy Providers 负责节点供应和状态维护
Proxies 负责真正建立出站连接

当配置出现问题时,也应该沿着这条链路排查:

text
流量有没有进入内核?

域名是否被正确识别?

规则命中了哪个策略?

策略组有哪些候选节点?

Provider 是否成功更新和测速?

最终节点能否建立连接?

只要保持职责边界清晰,Mihomo 即使配置项很多,也不会失去可维护性。

参考资料

Last updated:

基于 VitePress 构建 · 工程、交易与系统研究日志