为什么要从 dreamacro/clash 换成 mihomo?
我之前在群晖 NAS 上跑的是 dreamacro/clash,日常确实省心,但有一个很现实的问题:一些机场/节点开始以 VLESS 等较新的协议形态为主,或者直接给的是 Clash.Meta 风格订阅,这时候原版 Clash 的兼容性就会变得很尴尬——要么订阅吃不进去,要么能导入但实际连不通。
而 mihomo 可以理解为 Clash.Meta 系列内核的延续/实现(生态里常见的说法就是 “clash-meta aka mihomo”),对“较新协议与混淆/隧道方案”的支持更完整,所以我这次干脆一步到位换成 mihomo。
环境与前提条件
群晖系统:DSM 7.2
套件:Container Manager(或旧版 Docker 套件)
你已经有:可用订阅链接(Clash / Clash.Meta 订阅均可)
你希望达到的效果:
NAS 上能稳定跑代理内核;
有一个可视化面板(WebUI)管理节点/策略;
尽量少踩坑,出问题能快速定位。
整体思路
我们会用到两个容器(或一个内核 + 一个 UI):
mihomo(内核)
提供本地代理端口(HTTP/SOCKS/mixed)
提供控制接口
external-controller(默认常用 9090)
MetaCubeXD(WebUI 面板)
浏览器打开它(常用 9097)
它再去连接 mihomo 的 9090 控制接口
停掉旧 Clash(避免端口冲突)
如果你之前跑过 dreamacro/clashh 或者 haishanh/yacd 或类似内核,建议先停止容器,尤其注意是否占用了:
7890/7891/7892(代理端口常见)
9090(控制接口常见)
9090 被占用会导致 UI 连不上内核,表现通常就是 “Failed to fetch” 或“后端地址添加不上”。
创建目录
以群晖常见路径举例(你按自己的 volume 改):
/volume1/docker/mihomo/mihomo/:mihomo 配置与数据/volume1/docker/mihomo/mihomo/metacubexd/:MetaCubeXD 静态文件(可选)
你至少需要这些文件/目录:
mihomo/config.yaml、 geoip.dat 、 geosite.dat 、 geoip.metadb (如果你选择本地部署 metacubexd 静态文件)说明:不少教程会提醒你准备 geoip.dat / geosite.dat 这类文件,用于规则与地理库匹配,缺了不一定立刻报错,但“规则命中异常/体验不对”时它往往是隐患点之一。
Docker Compose 一把梭(推荐)
下面这份 compose 是“够用且好排查”的版本:一个 mihomo + 一个 metacubexd(UI)。端口可以自行更改:docker-compose.yml(路径自定义即可,我是放在第一个mihomo 目录下)的内容为:
# version: '3'
services:
mihomo:
container_name: mihomo
image: metacubex/mihomo
restart: always
privileged: true
pid: host
ipc: host
network_mode: host
cap_add:
- ALL
security_opt:
- apparmor=unconfined
volumes:
- /路径:/root/.config/mihomo # 更改为自己的路径
- /dev/net/tun:/dev/net/tun
metacubexd:
container_name: metacubexd
image: ghcr.io/metacubex/metacubexd
restart: always
network_mode: bridge
ports:
- '9097:80'
volumes:
- /路径:/config/caddy # 更改为自己的路径
整体而言,我的实现实在docker下面创建了一个mihomo文件夹,在mihomo文件夹下面创建了一个mihomo文件夹以及Docker Compose 模版文件,在子级mihomo文件夹下面创建了metacubexd文件夹以及config.yaml文件以及geoip.dat 、 geosite.dat 、 geoip.metadb。其中,geoip.dat 、 geosite.dat 、 geoip.metadb 文件在网址获取最新版本即可。详细的目录结构为:
mihomo/
├── docker-compose.yml
└── mihomo/
├── config.yaml
├── geoip.dat
├── geosite.dat
├── geoip.metadb
└── metacubexd/
└── (这里放 Metacubexd 的前端静态文件/资源,例如 dist/ 或 index.html 等)
接下来写配置文件,config.yaml(我的在第二个mihomo目录下面)的内容为(将订阅链接以及相应的名字更改为你自己的,我有两个,故写了两个,只有一个的话另一个删除即可, 同时, 需要设置登录密码的话secret解除注释并设置密码即可):
mixed-port: 7890
allow-lan: true
bind-address: '*'
mode: rule
log-level: info
external-controller: '0.0.0.0:9090'
#secret: ""
tun:
enable: true
stack: mixed
dns-hijack:
- "any:53"
- "tcp://any:53"
auto-route: true
auto-redirect: true
auto-detect-interface: true
proxy-providers:
订阅链接名字(自定义):
url: "订阅链接"
type: http
interval: 86400
health-check: {enable: true,url: "https://www.gstatic.com/generate_204", interval: 300}
override:
additional-prefix: ""
订阅链接名字(自定义):
url: "订阅链接"
type: http
interval: 86400
health-check: {enable: true,url: "https://www.gstatic.com/generate_204", interval: 300}
override:
additional-prefix: ""
proxies:
- name: "直连"
type: direct
udp: true
geodata-mode: true
geox-url:
geoip: "https://mirror.ghproxy.com/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat"
geosite: "https://mirror.ghproxy.com/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat"
mmdb: "https://mirror.ghproxy.com/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb"
asn: "https://mirror.ghproxy.com/https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb"
dns:
enable: true
ipv6: true
respect-rules: true
enhanced-mode: fake-ip
fake-ip-filter:
- "*"
- "+.lan"
- "+.local"
- "+.market.xiaomi.com"
nameserver:
- https://120.53.53.53/dns-query
- https://223.5.5.5/dns-query
proxy-server-nameserver:
- https://120.53.53.53/dns-query
- https://223.5.5.5/dns-query
nameserver-policy:
"geosite:cn,private":
- https://120.53.53.53/dns-query
- https://223.5.5.5/dns-query
"geosite:geolocation-!cn":
- "https://dns.cloudflare.com/dns-query"
- "https://dns.google/dns-query"
proxy-groups:
- name: 默认
type: select
proxies: [自动选择,直连,香港,台湾,日本,新加坡,美国,其它地区,全部节点]
- name: Google
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: Telegram
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: Twitter
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: 哔哩哔哩
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: 巴哈姆特
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: YouTube
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: NETFLIX
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: Spotify
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: Github
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
- name: 国内
type: select
proxies: [直连,默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择]
- name: 其他
type: select
proxies: [默认,香港,台湾,日本,新加坡,美国,其它地区,全部节点,自动选择,直连]
#分隔,下面是地区分组
- name: 香港
type: select
include-all: true
filter: "(?i)港|hk|hongkong|hong kong"
- name: 台湾
type: select
include-all: true
filter: "(?i)台|tw|taiwan"
- name: 日本
type: select
include-all: true
filter: "(?i)日|jp|japan"
- name: 美国
type: select
include-all: true
filter: "(?i)美|us|unitedstates|united states"
- name: 新加坡
type: select
include-all: true
filter: "(?i)(新|sg|singapore)"
- name: 其它地区
type: select
include-all: true
filter: "(?i)^(?!.*(?:|||||港|hk|hongkong|台|tw|taiwan|日|jp|japan|新|sg|singapore|美|us|unitedstates)).*"
- name: 全部节点
type: select
include-all: true
- name: 自动选择
type: url-test
include-all: true
tolerance: 10
rules:
- GEOIP,lan,直连,no-resolve
- GEOSITE,github,Github
- GEOSITE,twitter,Twitter
- GEOSITE,youtube,YouTube
- GEOSITE,google,Google
- GEOSITE,telegram,Telegram
- GEOSITE,netflix,NETFLIX
- GEOSITE,bilibili,哔哩哔哩
- GEOSITE,bahamut,巴哈姆特
- GEOSITE,spotify,Spotify
- GEOSITE,CN,国内
- GEOSITE,geolocation-!cn,其他
- GEOIP,google,Google
- GEOIP,netflix,NETFLIX
- GEOIP,telegram,Telegram
- GEOIP,twitter,Twitter
- GEOIP,CN,国内
- MATCH,其他
启动与验证
打开 Container Manmager – 项目 – 新增,项目名称:自己定义,路径为 docker-compose.yml的目录,会自动加载 docker-compose.yml,等待建立完成即可。
打开 UI(9097)并连接后端
访问:
UI:
http://群晖IP:9097
打开后的内容:
后端地址:
http://群晖IP:9090密钥:填你 config.yaml 里的
secret(没有设置就不填即可, 在config.yaml文件里面配置)
注意两个细节(非常高频的坑):
后端地址不要写 https。不少人图省事写了 https,结果浏览器安全策略/混合内容直接拦掉,UI 就会表现成 “Failed to fetch”。
如果你开了广告拦截/隐私插件,建议无痕模式或临时关闭插件测试一次。
初上手
在 mihomo / MetaCubeXD 里看到的 Global、自动选择、手动选择、DIRECT 这些卡片,本质上是 代理组(Proxy Group)。
理解它最简单的方式是:
节点是“刀”,代理组是“刀架”,规则是在说“什么菜用哪把刀”。
常见组类型(在面板里最常看到的):
GLOBAL(全局)
含义:不管访问什么域名/APP,统一走在 GLOBAL 里选的那一组/那一个节点。
适合:临时测试、“我就想一把梭”。
代价:国内直连也被代理走了,可能更慢。
自动选择(URLTest)
含义:内核会按延迟/可用性定期测一轮,在一堆节点里自动挑“当前最好用”的。
适合:不想天天手动换节点。
故障转移(Fallback)
含义:优先用主节点,挂了就切到下一个。
适合:稳定性优先的场景。
手动选择(Select)
含义:你点哪个就用哪个,不自动切。
适合:你对某条线路很有把握,或者需要固定出口 IP。
DIRECT(直连) / REJECT(拒绝)
含义:直连就是不走代理;拒绝就是直接拦掉。
适合:国内站点、广告域名、追踪域名等。
在面板的设置页面可以选择模式。
注意事项与建议
/dev/net/tun 不存在
docker-compose.yml中关于mihomo容器的配置里面有/dev/net/tun 路径的映射,在群晖里面可能会提示不存在(省心的方式:直接注释掉该行即可)
如果你要折腾 TUN(让 NAS“系统层面”更多流量透明走代理),群晖上经常会遇到:
/dev/net/tun does not exist
解决方法:在群晖控制面板 -> 任务计划 -> 新增 -> 触发的任务 -> 用户账号:root , 事件选择开机,在任务设置中填写的脚本为:
if [ ! -c /dev/net/tun ]; then
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 600 /dev/net/tun
fi
我个人建议:
如果只是“让 NAS 上的 Docker 拉镜像、让电脑手机能上网”,先别上来就搞 TUN。
先用
mixed-port + 规则模式 + WebUI跑顺,再决定是否透明代理,成本会低很多。
TUN 的好处在哪里?为什么很多人想用?
主要好处 1:不用每个应用单独设置代理很多设备/应用要么不支持代理,要么设置入口很深(甚至根本没有代理设置)。
TUN 接管后,这些流量也能被 mihomo 统一处理。典型场景:
NAS 上某些 Docker 容器/服务访问外网(拉镜像、插件更新)
某些客户端不支持 SOCKS/HTTP 代理,但仍想走代理
想要更接近“像路由器一样”统一代理的体验
主要好处 2:规则更“真实”
如果只是靠浏览器设置代理,很多系统服务、后台进程的流量根本不经过 mihomo;
TUN 接管后,mihomo 能看到更完整的连接请求,你的规则分流才更符合预期。主要好处 3:对“非 HTTP 流量”更友好
很多协议不是 HTTP(例如某些游戏、系统更新、特定客户端协议)。
只要是 IP 流量,理论上都能被 TUN 接管进来再决定如何处理。
反向代理与安全建议:别把控制口裸到公网
很多人喜欢把 UI 用域名/HTTPS 反代出去,我也理解:在外面用手机看面板很爽。
但我必须认真提醒一句:
9090 是控制接口,它不是给公网随便访问的。
真要暴露,也至少做到:
强 secret
IP 白名单(只允许你自己的出口 IP)
或者加一层鉴权(Basic Auth / OAuth / VPN)
如果你用 Nginx 反代,最少也建议做“只允许指定 IP 段访问”,避免把 NAS 变成公共靶子。

