mihomo配置学习

22 min read,created at 2026-09-25
vpnmihomoclash

1 前言

mihomo是目前用的最多的vpn客户端,大多数机场也都是分发的mihomo格式的订阅链接为主,他的前身是clash.meta,最终自clash演进而来,不过clash已经被约谈,2023年停止更新了。clash派系是yaml配置格式,也是本文介绍的重点。其他的vpn比如sing-box、v2rayn等都是json格式,我们这里不做讨论。

mihomo配置的最简单形式如下:

mixed-port: 7890                 # HTTP + SOCKS5 混合端口
allow-lan: false                 # 是否允许局域网设备连接
mode: rule                       # rule / global / direct
log-level: info                  # silent / error / warning / info / debug

proxies:                         # 节点配置
  - name: "一个socks5代理节点"
    type: socks5                 # 协议socks5/http/vmess/ss/ssr/trojan/vless/wireguard/anytls
    server: "11.1.1.111"
    port: 3000
    username: "xxxx" 
    password: "xxxxx"
    udp: false

proxy-groups:                    # 代理组配置(多个节点放到一个分组,方便切换)
  - name: "youtube分组"
    type: select
    proxies:
      - "一个socks5代理节点"

rules:                           # 规则配置(按照域名/ip 后缀/关键字等匹配后,指向特定分组)
  - DOMAIN-SUFFIX,google.com,DIRECT
  - DOMAIN-SUFFIX,youtube.com,youtube分组

2 基础配置

全局level的配置,主要是一些mihomo自身的配置,比如监听的端口,是否允许局域网连接。上面例子中已经列出了

mixed-port: 7890                 # HTTP + SOCKS5 混合端口
allow-lan: false                 # 是否允许局域网设备连接
mode: rule                       # rule / global / direct
log-level: info                  # silent / error / warning / info / debug

如果允许局域网被其他机器连接,通常还需要有以下配置:

allow-lan: true
authentication:              # 不配置的话,就是局域网裸奔
  - "alice:Passw0rd"
  - "bob:123456"             # 可以配多个账号:密码
skip-auth-prefixes:          # 这些来源 IP 免密
  - 127.0.0.1/8
  - ::1/128

如果想要配置多个端口,以及不同端口不同协议也是可以的,使用listeners配置项,但是一般不太会用到,这里不展开了。

mihomo还提供了一个rest接口的api,需要用的话,要在配置中开启:

external-controller: 127.0.0.1:9090    # 只允许本机访问 0.0.0.0:9090允许局域网
secret: "一串随机密码"                  # API鉴权,不加就是裸奔
external-ui: ./ui                      # 可选:让内核直接托管网页面板

启动一个mihomo,最简单的方式就是直接用docker方式:

# -d 是指定config.yaml文件的路径
docker run --rm \
-p 17890:7890 -p 19090:9090 \
-v ./config.yaml:/config.yaml metacubex/mihomo \
-d /

为了避免和本机已有的7890等端口冲突,这里我映射到了17890和19090,接下来打开http://127.0.0.1:19090就可以看到UI了,这个ui和很多vpn客户端就已经非常相似了。

image

可以看到默认是有一个代理节点的,就是DIRECT,也就是直连。

3 sniffer

sniffer嗅探是一个根据IP反向解析出域名的能力,一般这样配置

sniffer:
  enable: true
  parse-pure-ip: true
  sniff:
    TLS:
      ports:
      - 443
    HTTP:
      ports:
      - 80
      override-destination: true

他在什么时候起作用呢?如果你使用的不是tun模式,并且还是用的socks协议,而不是http协议的时候,此时如果不配置嗅探就会发现:

$ curl -x socks5://127.0.0.1:7890  https://www.youtube.com -I
curl: (35) schannel: failed to receive handshake, SSL/TLS connection failed

$ curl -x http://127.0.0.1:7890  https://www.youtube.com -I
HTTP/1.1 200 Connection established
HTTP/1.1 200 OK
xxxxxxxxxxxxxx

$ curl -x socks5h://127.0.0.1:7890  https://www.youtube.com -I
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
xxxxxxxxxxxx

也就是sock5挂了,但是http和sock5h没问题,这是因为dns解析的位置不同,http代理的时候,客户端是把域名送到代理服务器,而socks5代理的时候,是在客户端dns解析完成之后,把ip发给代理服务器。这就导致如果你mihomo配置了DOMAIN-SUFFIX,youtube.com,油管分组的规则(我们后面会说rule),但是此时送过来的是ip地址,并不满足域名的规则,而油管的ip可能没有配置rule,最终变成了直连导致出错。

而sniffer嗅探就在这个时候起作用了,他会拿到ip之后发现端口是443,命中了规则,就去尝试解析ip的域名发现是油管,然后再走rule命中了正确的规则,于是就通了,所以在增加了嗅探之后上面的socks5也可以成功了。

curl -x socks5://127.0.0.1:7890  https://www.youtube.com -I
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
xxxxxx

不过sock5h这个写法也可以不用嗅探他也会让dns解析发生在mihomo,和http类似,这也是现在很多客户端包括chrome走代理的时候其实用的是socks5h的原因,而嗅探大多数时候也不太需要配置了。但作为理解代理原理和流程的一个重要环节,这里依然要说一下。

4 tun

tun隧道、虚拟网卡模式,这是一个非常常用的模式,如果没有tun的话,mihomo只是一个代理服务器,最多就是配置为系统代理,也就是HTTP_PROXY、HTTPS_PROXY等环境变量配置,但是很多程序并不会读这个环境变量进行代理设置,还有很多程序用的不是http协议,而是基础的tcp或者其他上层协议,这就导致很多应用是无法使用代理服务器的。

而tun就是为了解决这一问题,直接抽象出一个虚拟网卡在本机,然后把所有的网络流量都走这张新的网卡,并劫持了所有的网络流量,这个可谓是比设置系统代理更好用更彻底的解决方案,不管你应用是否漏了HTTP_PROXY等环境变量的处理,还是没有用http协议,统统都要走网卡,而都会被tun抓住,进行处理。现在tun已经是一种非常主流的使用方式了。

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

虚拟网卡底层有三种实现方式stack,建议用gvisor或mixed,先保证兼容性,调通了,再看看性能更好的system方案是否可行。

名称描述兼容性
system借用操作系统内核自带的 TCP/IP 协议栈性能最好、CPU 占用低;在 Windows 上需要防火墙放行,部分环境下兼容性较差
gvisor用户态协议栈(来自 Google 的 gVisor 项目)兼容性最好,不依赖系统网络栈;CPU 占用略高
mixedTCP 使用 system,UDP 使用 gvisor兼顾性能和兼容性

auto-route是否接管系统的网络流量,如果设为false,等于只放一张网卡,实际流量不走过来。

strict-route严格路由,最大限度避免有漏网之鱼的,一般不需要那么严格,保持false即可。

auto-detect-interface自动检测出口的网卡,因为虚拟网卡是拦截系统流量,最后流量还要从实体网卡出去,这里要设置为true会自动发现从哪里出去,比如可能是eth0。

dns-hijack是tun模式下拦截操作系统的dns解析,因为默认情况下开了tun就不需要再指定proxyServer地址了,那默认curl google.com就会走系统的dns解析,会有两个主要的问题

  • 1 可能就会解析到污染的地址,ip就是错的
  • 2 ip即使是对的,域名ip的映射并没有在mihomo缓存,tcp网络流量还是用的ip,如果不配置嗅探的话,还是和之前sock5一样走到错误的分组中。

所以一定要配置这个dns劫持,这里配置的是any:53,也就是本机任意ip的udp53端口作为dns服务器,后面会介绍这个要配合一个dns的配置。

5 dns

dns是配置一个自建的dns服务器,主要作用是用于tun模式的dns解析的系统操作的拦截。

dns:
  enable: true
  listen: :53
  ipv6: true                # 是否解析域名的ipv6地址(需要本机有ipv6,否则没啥用)
  prefer-h3: false          # 是否prefer http3
  default-nameserver:       # 引导DNS,主要是解析其他Doh(dns on hppts)的域名用的
  - system                  # 系统原来的dns服务器
  - 8.8.8.8                 # 只能用ip格式,否则死锁了
  - 2400:3200::1
  - 2001:4860:4860::8888
  nameserver:                         # 默认dns,大部分都用这个来解析
  - 8.8.8.8                  
  - https://doh.pub/dns-query         # Doh的,这个域名就需要用default的解析
  - https://dns.alidns.com/dns-query
  proxy-server-nameserver:            # 代理节点的dns解析,节点也可能是域名格式,就会用这个解析
  - https://doh.pub/dns-query
  - https://dns.alidns.com/dns-query
  - tls://223.5.5.5
  direct-nameserver: []               # 直连时候的dns,没配则兜底到nameserver
  direct-nameserver-follow-policy: false

  respect-rules: false  # DNS 查询是否也按 rules 分流,没必要,false即可

  use-hosts: false        # 是否用hosts配置中的值覆盖
  use-system-hosts: false # 是否用系统hosts配置中的值覆盖


  enhanced-mode: fake-ip    # fake-ip/redir-host,fake-ip的话,后续的fake-xxx配置才生效
  fake-ip-filter:           # fake-ip模式下,过滤的域名,可以是域名或者ip
  - '*.lan'
  - '*.local'
  - '*.arpa'
  - time.*.com
  - ntp.*.com
  - time.*.com
  - +.market.xiaomi.com
  - localhost.ptlogin2.qq.com
  - '*.msftncsi.com'
  - www.msftconnecttest.com
  - mini.local
  fake-ip-filter-mode: blacklist  # filter是黑名单模式
  fake-ip-range: 198.18.0.1/16    # fake的ip都是这个网段的
  fake-ip-range6: fdfe:dcba:9876::1/64 # v6

上面的配置已经加了注释,大部分比较清晰了,只是后面的fake-ip可能比较困惑。其实mihomo的dns有fake-ip常见和redir-host两种模式,为啥有这两种呢?这和网络流程有关。

例如curl google.com,本质上是不需要我们本机做dns解析的,只需要把google.com直接送到代理节点(梯子)那边,代理节点会自己做dns解析的。但是操作系统的网络传输流程是固定的,先进行dns解析,然后向ip发包。

所以redir-host模式下,是先解析google的ip(用nameserver配置的dns),然后把ip -- google.com的映射记录到内存中,后面再发包的时候,会查出来是google.com,就明中分组,把域名格式的请求发送到proxy节点。核心思路就是需要mihomo自己缓存一个mapping,这样后续的ip发包能知道是哪个域名,这样比嗅探更稳。

但是redir-host下有个没啥用的操作就是本地的这个dns解析,其实ip -- goolge.com只需要记录一个假的占位符ip,比如0.0.0.1,这样后续发到0.0.0.1的包,映射回google.com就行了,proxy节点才是最终的dns解析。这就是fake-ip的思路,比如上面配置中,fakeip模式会给所有的域名都解析到198.18.x.x网段,这就是个假的ip并不是真的dns解析后的结果,这样省了第一次dns解析的时间,因为不需要正确的ip,所以能省了这个时间,但是我个人不建议用fake-ip,fake之后你会发现,你ping www.google.com返回的也是这个198.18.x.x,redir-host并没有多占用多少时间(多一次dns解析),因为dns解析本身也会缓存,只有第一次会稍慢一点。

6 proxies

proxies是每个代理的节点详情,例如

proxies:
- name: "[Normal]Hong Kong 03"
  type: anytls
  server: zbbfxzui.znnfxzui.cc
  port: 3443
  password: xxxx
  udp: true
  sni: speedtest-hongkong-hk-normal-03.grandmacdn.cc

这部分大部分时候都是机场自己生成好的批量节点信息,其中type取值较多:

type协议特点
http / socks5普通代理明文、无混淆,一般只用于内网或链式代理的某一跳
ssShadowsocks简单、快,机场最常用
ssrShadowsocksR已经过时
vmessV2Ray 的协议老牌协议,常配合 WebSocket + TLS
vlessVMess 的精简版本身不加密,依赖 TLS 或 Reality,目前主流
trojan伪装成 HTTPS必须使用 TLS
hysteria2基于 QUIC(UDP)在网络质量差、丢包严重时速度优势明显
tuic基于 QUIC和 hysteria2 类似
wireguardWireGuard VPN常用于连接 WARP 或自建的 WireGuard 服务
anytls见下文较新的协议(25年才有的)
ssh / snell / mieru其他协议使用较少
direct / dns特殊出站自定义的直连出站 / 把流量交给 DNS 模块处理

不同协议要求配置的字段会有较大差异,这里不详细展开了,主要是其中的server和port,password这几项基本是必须的。

另外要说一下http/socks5协议可以作为下游的协议,并且同时也是mihomo对外透出的协议类型,主要用于内网,在某些网站购买的住宅ip也是这种简单协议,一般不要直接通过本地连接这种ip过去,因为socks5明文很容易被抓住,所以很多住宅ip是不允许直接从国内连过来,这就需要拨号模式,或者叫两跳。

proxies:
  - name: "机场首跳"                         # 一个机场的节点
    type: anytls
    server: zbbfxzui.znnfxzui.cc
    port: 3443
    password: xxxx
    udp: true
    sni: speedtest-hongkong-hk-normal-03.grandmacdn.cc
  - name: "住宅出口"
    type: socks5
    server: "us.1024proxy.io"
    port: 3000
    username: "xxxx" 
    password: "xxxxx"
    dialer-proxy: "机场首跳"                 # 配置住宅节点的dialer-proxy是机场节点
    udp: false

这样配置后,住宅出口这个节点就会先用机场作为第一跳。

7 proxy-groups

代理节点分组,前面的proxy节点一个机场可能有50个,然后有些可以给youtube,有些可以给openai等等,这样为了更好的组织和管理就有了分组。

proxy-groups:
  - name: "youtube分组"
    type: select                # 默认始终取第一个节点,除非通过ui或api改,所以不太适合自动化,
    proxies:
      - "香港01"
      - "香港02"
      - "美国01"
      - "美国02"

  - name: "openai分组"
    type: fallback              # 默认第一个可用的节点,然后每5min测试找到一个可用的节点
    url: https://www.gstatic.com/generate_204 # 测试到这个url是否可达
    interval: 300
    proxies:
      - "美国01"
      - "美国02"

  - name: "ins分组"
    type: url-test              # 取延迟最低的,翻墙常用的
    interval: 300               # 每5min测试一次
    tolerance: 50               # 新节点要比当前节点快 50ms 以上才会切换,避免频繁跳来跳去
    url: https://www.gstatic.com/generate_204 # 测试到这个url的延迟
    proxies:
      - "美国01"
      - "美国02"

  - name: 负载均衡              # 普通翻墙不太会用
    type: load-balance
    proxies: [香港01, 香港02, 香港03]
    url: https://www.gstatic.com/generate_204
    interval: 300
    strategy: consistent-hashing

分组主要起到一个好管理的作用,前面的dialer-proxy也可以指向分组名,而不是proxy名,这样如果分组本身又是url-test类型的话,就可以在链式vpn,第一跳选择延迟最低的节点,第二跳再走住宅出口ip了。

在mihomo的配置中,proxy节点name和,proxy-group的name在很多地方都是一样的地位。

8 rules

rules是对代理节点的规则配置,比如youtube.com的域名要走youtube分组,规则是数组,从上到下匹配,一般最后一条是MATCH,漏网之鱼group。

rules:
  # 1 youtube.com 走youtube分组
  - DOMAIN-SUFFIX,youtube.com,youtube分组
  # 兜底
  - MATCH,漏网之鱼

DOMAIN相关的匹配方式如下,其中后缀和关键词用的最多

- DOMAIN,www.google.com,X	#只匹配完全相同的域名
- DOMAIN-SUFFIX,google.com,X	#google.com 本身及其所有子域名
- DOMAIN-KEYWORD,youtube,X	#域名中包含这个关键词
- DOMAIN-WILDCARD,*.google.*,X	#通配符(* 匹配任意字符,? 匹配单个字符)
- DOMAIN-REGEX,^ads?\..*,X	#正则表达式
- GEOSITE,youtube,X	#使用 geosite 数据库中的分类

IP相关的有:

- IP-CIDR,192.168.0.0/16,DIRECT	#IPv4 网段
- IP-CIDR6,2001:db8::/32,DIRECT	#IPv6 网段
- IP-SUFFIX,8.8.8.8/24,X	#按 IP 的最后几位匹配
- IP-ASN,13335,X	#按自治系统编号匹配(13335 是 Cloudflare)
- GEOIP,CN,DIRECT   #按 IP 所属国家或地区匹配
- GEOIP,CN,DIRECT,no-resolve # 来的是域名,则不解析出ip,直接跳过这条规则

还有进程、来源和端口、逻辑组合等规则,属于高级用法,且翻墙的话基本不太会用,这里不展开。

9 proxy-providers

proxy-providers是一些可以自定义代理节点的提供者,比如把某个机场作为一个供应商。

如下从url拉取节点列表(url的配置不止节点,这里只会拉取节点),然后缓存到本地airport.yaml,每天更新,并且根据过滤器过滤掉不合法的节点。

proxy-providers:
  airport:
    type: http
    url: "https://sub.xxx/s/xxxxx"
    path: ./providers/airport.yaml
    interval: 86400
    proxy: DIRECT            # 下载订阅文件,用直连
    health-check:
      enable: true
      url: https://www.gstatic.com/generate_204
      interval: 300
      timeout: 5000
    filter: '(?i)(United States|Singapore|美国|新加坡|🇺🇸|🇸🇬|\bUS\b|\bSG\b)'

然后可以在分组里面用这个供应商,并改为url-test取这个机场的节点中最快的。

proxy-groups:
  - name: "机场1"
    type: url-test
    use:
      - airport
    url: https://www.gstatic.com/generate_204
    interval: 300
    tolerance: 100

10 机场订阅该如何使用

机场的订阅链接的内容是一个完整的config.yaml的配置,至少包括了proxies节点,proxy-groups和rules,这是三个最终要的。有了这三个,基本能满足大部分人的科学上网了。

一般通过输入配置文件url就可以导入,而上面的prxoy-providers的配置方法,也可以不用依赖某一家机场的订阅,可以把多家机场都作为provider,自己来打平了编排这些node节点,比如挑两个机场中最快的一个节点。