Clash 多设备配置同步:订阅链接、托管配置与手动导出三种方案
手机、电脑、平板之间如何让配置保持一致:对比订阅链接自动同步、自建配置托管与手动导出导入三种方案的适用场景、维护成本与冲突处理方式。
先分清要同步的是哪几样东西
多设备之间「配置对不上」,多数时候不是客户端的问题,而是把几类性质不同的数据混在一起管理了。它们存放的位置、更新方式、能否自动同步都不一样,先分清楚再谈方案。
| 数据 | 存放位置 | 能否自动同步 |
|---|---|---|
| 订阅链接 | 各客户端的配置库 | 否,每台设备各填一次 |
配置本体 config.yaml | 客户端配置目录或托管 URL | 是,拉取订阅时整体替换 |
| 节点与规则集 providers | ./providers、./ruleset 缓存 | 是,按 interval 定时拉取 |
| 当前选中节点、运行模式 | 客户端运行状态 | 否,各设备独立 |
真正需要统一的是配置本体和 providers 缓存:前者决定端口、DNS、TUN 与规则,后者决定节点列表。至于当前选中的是哪个节点、mode 停在 rule 还是 global,本来就该按设备分别设,不必强求一致。
一个常见误判:订阅相同不等于配置相同
订阅只决定节点来源。mixed-port、dns、tun、rules 这些字段由各客户端在本地维护,换订阅不会同步端口,也不会同步本地规则。所以「三台设备填了同一个链接」和「三台设备行为一致」是两件事,后者要靠下面的方案来保证。
方案一:订阅链接自动同步
三台设备填同一个订阅地址,客户端按固定间隔自动拉取。桌面、Android、iOS 都支持,是覆盖面最广的做法,也是维护成本最低的一种。
「订阅」→「新建」,粘贴订阅地址后保存,先不要急着开代理。
右键订阅卡片 →「编辑」,把自动更新间隔从默认的 1440 分钟改成 360~720 分钟。
右键订阅卡片 →「更新」,确认能拉出完整节点列表,而不是只剩一个配置名。
「设置」→「系统代理」按需开启;TUN 模式在「设置」→「TUN 模式」单独打开,移动端由客户端的 VPN 服务接管,不需要额外配置。
Android 端在「配置」列表里长按配置可看到更新入口,iOS 端在配置详情页下拉刷新。
rules、mixed-port、dns 段,更新后这些字段会被订阅里的值覆盖。把自建规则直接写进订阅配置,是「更新一次丢一次」最常见的原因。
端口被改写之后的表现
订阅把 mixed-port 从 7890 改成 7891 之后,系统代理和浏览器插件里写死的 7890 仍然指向旧端口,表现是客户端显示已连接、但网页全部打不开。核对办法是打开 external-controller 面板(默认监听 127.0.0.1:9090)看实际生效的端口。
# 查看当前生效的端口、模式与 DNS 设置
curl -s http://127.0.0.1:9090/configs
不方便用命令行的,直接看桌面客户端「设置」页显示的端口,和浏览器插件里的值对一下即可。
适用边界
- 适合:设备数 1~3 台,规则完全跟随订阅,不想额外维护文件。
- 不适合:有自建规则、需要按设备区分端口、订阅结构经常调整。
方案二:自建配置托管,一份 YAML 管所有设备
把配置本体放到一个能直连下载的地址(私有对象存储、自建 nginx、私有仓库的 raw 链接都可以),各设备把这个地址当作订阅导入。之后改规则只改这一份文件,各端下次拉取时自动生效。
把节点来源和规则解耦
不要把节点直接写进 proxies,用 proxy-providers 让内核自己去拉节点;端口、DNS、规则这些属于你自己的部分,全部写在 base config 里。
mixed-port: 7890
allow-lan: false
mode: rule
log-level: warning
external-controller: 127.0.0.1:9090
unified-delay: true
tcp-concurrent: true
proxy-providers:
airport-a:
type: http
url: "https://sub.example.com/api/v1/client/subscribe?token=9f2c1a7b4e"
interval: 3600
path: ./providers/airport-a.yaml
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 300
timeout: 3000
rule-providers:
reject:
type: http
behavior: domain
format: mrs
url: "https://example.com/rules/reject.mrs"
path: ./ruleset/reject.mrs
interval: 86400
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- https://223.5.5.5/dns-query
fallback:
- https://1.1.1.1/dns-query
两个 interval 的单位都是秒:3600 表示一小时拉一次节点,86400 表示一天拉一次规则集。节点变动频繁就把前者调到 1800,规则集没必要更勤。
format: mrs 需要 mihomo 1.18.0 及以上,老版本改用 format: yaml 配 behavior: domain。另外,托管地址必须能直连下载,放在需要代理才能访问的地方,首次启动会拉不到配置,表现是节点列表为空。
上线前先本地过一遍语法
# 只做配置检查,不启动代理
mihomo -t -d /etc/mihomo -f config.yaml
检查通过再提交到托管地址。各设备导入托管 URL 之后,节点由 providers 定时拉取,改规则只需要各端重新拉一次配置,不用逐台改。
字段与内核版本的对应关系
| 字段 | 可用版本 | 作用 |
|---|---|---|
format: mrs | mihomo 1.18.0 起 | 规则集二进制格式,体积更小、加载更快 |
tcp-concurrent | mihomo 1.16 起 | 并发建连,减少握手等待 |
unified-delay | mihomo 1.16 起 | 统一各协议的延迟测量口径 |
geodata-mode | mihomo 1.16 起 | 选择内置 GEO 数据的使用方式 |
方案三:手动导出导入
只在离线设备、路由器或临时调试时值得用。做法是导出配置本体,连 providers/、ruleset/ 缓存目录一起复制过去,缺了缓存目录会白跑一趟。
桌面客户端在「设置」里点「打开配置目录」;mihomo 命令行版通常在 /etc/mihomo/config.yaml 或 ~/.config/mihomo/config.yaml。
只拷贝 config.yaml 时,首次启动会因为 providers 缓存缺失而显示节点列表为空。
例如 config-20260830.yaml,避免客户端里堆好几份同名配置互相覆盖。
iOS 端先用「文件」App 或云盘把 YAML 存到本机,再在客户端里选择「导入配置」。
看「代理」页的节点数量与「规则」页的条数,和源设备一致才算导入成功。
以下几种情况基本只能走手动这条路:
- 目标设备访问不到托管地址,比如内网或离线环境。
- 只想临时验证一条规则或一组 DNS 设置,不想动托管文件。
- 路由器等嵌入式环境,只能通过 U 盘或 SCP 放文件。
冲突处理:把改动分层
三种方案混用时,冲突基本来自同一个原因——同一个字段被两处修改。解决办法是把改动分层:订阅或托管文件只放公共部分,设备差异放在合并层。
合并层只写差异
# Merge 配置:不复制整份 config.yaml,只写要改的部分
prepend-rules:
- DOMAIN-SUFFIX,intranet.example.com,DIRECT
prepend-proxy-groups:
- name: 手动选择
type: select
proxies: [自动选择, DIRECT]
规则用 prepend-rules 插到最前面,匹配优先级高于订阅自带规则;代理组用 prepend-proxy-groups 放到列表顶部,方便在界面上直接选。订阅更新时,合并层的内容不会被覆盖,这是它比「直接改订阅配置」可靠的地方。
一致性核对清单
| 核对项 | 位置 | 期望结果 |
|---|---|---|
| 生效端口 | 「设置」→「端口」,或 GET /configs | 各设备同为 7890 |
| 节点数量 | 「代理」页 | 同一 provider 拉取的节点数一致 |
| 规则条数 | 「规则」页 | 与托管文件里的 rules 条数一致 |
| provider 更新时间 | GET /providers/proxies | 落在 interval 之内 |
| 运行模式 | 托盘菜单或首页 | 日常保持 rule,排查时才切 global |
# 看 provider 最近一次拉取时间与节点数量
curl -s http://127.0.0.1:9090/providers/proxies
一条经验规则:同一个字段只允许一个地方定义。端口、DNS、TUN 写在 base config;节点来源写在 proxy-providers;设备差异写在合并层;选中节点和运行模式交给各设备自己。做到这一点,三台设备之间的差异就只剩「当前选了哪个节点」。
局域网里的两个注意点
external-controller默认只监听127.0.0.1,要让别的设备访问面板,需要显式改成0.0.0.0:9090并设置secret。- 多台设备同时开
allow-lan不会互相冲突,但其它设备要指向正确的设备 IP,端口保持 7890 即可。
三种方案怎么选
| 方案 | 适用场景 | 维护成本 | 冲突处理 |
|---|---|---|---|
| 订阅链接自动同步 | 1~3 台设备,规则跟随订阅 | 低 | 各自覆盖,本地改动会丢 |
| 自建配置托管 | 3 台以上,有自建规则 | 中 | 合并层分层,冲突可预期 |
| 手动导出导入 | 离线设备、路由器、临时调试 | 高 | 全量覆盖,需人工核对 |
最常见的组合是:主设备用托管 URL 加合并层,手机和备用机直接填订阅链接,路由器这类不方便联网更新的设备手动放文件。三套并存时,只要保证同一个字段只有一个定义处,就不会互相打架。
常见问题
手机和电脑填了同一个订阅,节点数量却不一样
&flag=clash 这类参数,结果就会不同。订阅更新后本地规则没了,怎么保住
prepend-rules;不支持合并链的客户端,改用自建托管 URL,把规则写进 base config 的 rules 段。同一份配置在 macOS 上正常,Android 上启动就报错
tun、redir-port、tproxy-port 属于桌面和 Linux 侧的写法,Android 由客户端自己的 VPN 服务接管;external-controller 写成 0.0.0.0:9090 又没配 secret 时,部分客户端会直接拒绝启动。把这些字段从 base config 移出,放进各端的合并层即可。多台设备同时开 TUN 模式会冲突吗
allow-lan,注意让其它设备指向正确的设备 IP;面板端口默认只监听本机,跨设备访问要显式放开并设置 secret。