Clash 多设备配置同步:订阅链接、托管配置与手动导出三种方案

手机、电脑、平板之间如何让配置保持一致:对比订阅链接自动同步、自建配置托管与手动导出导入三种方案的适用场景、维护成本与冲突处理方式。

先分清要同步的是哪几样东西

多设备之间「配置对不上」,多数时候不是客户端的问题,而是把几类性质不同的数据混在一起管理了。它们存放的位置、更新方式、能否自动同步都不一样,先分清楚再谈方案。

数据存放位置能否自动同步
订阅链接各客户端的配置库否,每台设备各填一次
配置本体 config.yaml客户端配置目录或托管 URL是,拉取订阅时整体替换
节点与规则集 providers./providers./ruleset 缓存是,按 interval 定时拉取
当前选中节点、运行模式客户端运行状态否,各设备独立

真正需要统一的是配置本体和 providers 缓存:前者决定端口、DNS、TUN 与规则,后者决定节点列表。至于当前选中的是哪个节点、mode 停在 rule 还是 global,本来就该按设备分别设,不必强求一致。

一个常见误判:订阅相同不等于配置相同

订阅只决定节点来源。mixed-portdnstunrules 这些字段由各客户端在本地维护,换订阅不会同步端口,也不会同步本地规则。所以「三台设备填了同一个链接」和「三台设备行为一致」是两件事,后者要靠下面的方案来保证。

方案一:订阅链接自动同步

三台设备填同一个订阅地址,客户端按固定间隔自动拉取。桌面、Android、iOS 都支持,是覆盖面最广的做法,也是维护成本最低的一种。

新建订阅

「订阅」→「新建」,粘贴订阅地址后保存,先不要急着开代理。

改自动更新间隔

右键订阅卡片 →「编辑」,把自动更新间隔从默认的 1440 分钟改成 360~720 分钟。

手动更新一次

右键订阅卡片 →「更新」,确认能拉出完整节点列表,而不是只剩一个配置名。

按设备决定代理入口

「设置」→「系统代理」按需开启;TUN 模式在「设置」→「TUN 模式」单独打开,移动端由客户端的 VPN 服务接管,不需要额外配置。

其余设备重复以上步骤

Android 端在「配置」列表里长按配置可看到更新入口,iOS 端在配置详情页下拉刷新。

订阅更新会整体替换配置本体 订阅文件里如果带 rulesmixed-portdns 段,更新后这些字段会被订阅里的值覆盖。把自建规则直接写进订阅配置,是「更新一次丢一次」最常见的原因。

端口被改写之后的表现

订阅把 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: yamlbehavior: domain。另外,托管地址必须能直连下载,放在需要代理才能访问的地方,首次启动会拉不到配置,表现是节点列表为空。

上线前先本地过一遍语法

# 只做配置检查,不启动代理
mihomo -t -d /etc/mihomo -f config.yaml

检查通过再提交到托管地址。各设备导入托管 URL 之后,节点由 providers 定时拉取,改规则只需要各端重新拉一次配置,不用逐台改。

字段与内核版本的对应关系

字段可用版本作用
format: mrsmihomo 1.18.0 起规则集二进制格式,体积更小、加载更快
tcp-concurrentmihomo 1.16 起并发建连,减少握手等待
unified-delaymihomo 1.16 起统一各协议的延迟测量口径
geodata-modemihomo 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 上启动就报错
平台相关字段不同。tunredir-porttproxy-port 属于桌面和 Linux 侧的写法,Android 由客户端自己的 VPN 服务接管;external-controller 写成 0.0.0.0:9090 又没配 secret 时,部分客户端会直接拒绝启动。把这些字段从 base config 移出,放进各端的合并层即可。
多台设备同时开 TUN 模式会冲突吗
不会,每台设备的 TUN 只在本机生效。同一局域网里如果都开了 allow-lan,注意让其它设备指向正确的设备 IP;面板端口默认只监听本机,跨设备访问要显式放开并设置 secret
下载 Clash 客户端