← 返回博客

2026年自建节点统一订阅化完全指南:把VPS自建节点和机场订阅合并成一份Clash/sing-box订阅

📌 一分钟总结

机场订阅能自动更新,自建节点却要在每台设备手动导入?本文把自建节点变成可订阅、可一处维护多端同步的订阅源:3X-UI 面板订阅服务配置、mihomo 三个 provider 合并、sing-box 配置生成、Sub-Store 组合订阅编排、自建与机场的分工分流、多端分发与订阅失效兜底,附 10 个高频坑与 12 个 FAQ。

📑 目录

自建节点的日常大概是这样:新买一台 VPS,在面板里点几下建好节点,然后手机导入一次、电脑导入一次、软路由再导入一次;半年后 IP 被墙或机房线路调整,这套动作要全部重做一遍。机场订阅只有一条链接:后台更新节点,所有设备下次自动更新就同步了。

差的不是节点质量,而是分发方式——本文要解决的正是这一层:把自建节点变成可订阅、可自动更新、可一处维护多端同步的订阅源,再和机场订阅合并成一份统一配置,让手机、电脑、软路由、NAS 吃同一份输出。节点怎么搭、协议怎么选不属于本文范围,已经写过的不重复。

路线按「选型 → 建订阅源 → Clash 合并 → sing-box 处理 → Sub-Store 编排 → 分工分流 → 多端分发 → 兜底排坑」推进,所有代码片段都可以直接抄改。

一、先对齐概念:自建节点缺的不是「节点」,是「分发方式」

先分清两个东西。自建节点本质上是一串节点链接:ss://、vmess://、vless://、trojan://、hysteria2://,它们是节点参数的编码,谁拿着谁就能连,但它们不会自己更新、也不会自己分发。

机场订阅本质上是一个 URL:服务端按客户端请求动态生成节点列表,客户端按配置的间隔定时拉取。地址不变,内容可变,这才是订阅的价值。

把两件事放在一起看,自建节点差的是四件事:

维度自建节点(手动导入)机场订阅自建节点订阅化之后
更新成本换了 IP / 端口要逐台设备重配后台改完,客户端自动同步改一次面板,所有端自动同步
多端一致性容易漂移:手机上是旧 IP,路由上还是更旧的一致,都拉同一个 URL一致,自建与机场在同一条链路上
失效感知节点死了才在客户端里发现健康检查 + 订阅更新健康检查 + 自动切换
可编排性无法统一改名、过滤、去重可被转换器/Sub-Store 编排与机场节点一起被编排

机场订阅的省心是实打实的:后台调整节点后,客户端下一次自动更新就同步完成,不用碰任何设备。自由猫 这类订阅就是典型形态,一条 URL 管住手机、电脑、软路由三端。自建节点默认没有这层能力,但它并非做不到,只是你还没给它做一个「订阅源」——这就是下面三节要做的事。

二、四种统一路线:先选路线,再动手

统一订阅化有四条成熟路线,难度和维护成本差别很大,别一上来就选最复杂的。

路线代表工具前置条件一处维护多端同步难度适合谁
① 客户端本地合并Clash Verge Rev(mihomo 内核)、sing-box无,每台设备各配一次❌ 每端要分别改低设备少、只有一个机场 + 一两台 VPS
② 面板自带订阅3X-UI / X-UI 的订阅服务自建节点跑在面板上⚠️ 自建节点能同步,机场侧仍要各自导低所有自建都走面板的人
③ Sub-Store 编排Sub-Store(本机 / VPS / 软路由 / Worker 部署)一个常开的运行位置✅ 真正同步:一份输出给所有端中多设备 + 自建 + 机场混用
④ 服务端转换器subconverter(自建)一台服务器 + 会改配置✅ 同步,兼容面最广中高要给老客户端 / 多格式输出

一个快速的判断口径:只有机场订阅、设备在 3 台以内,路线①够用;自建节点跑在面板上,路线②是成本最低的起点;设备超过 3 台、并且希望「任何一端都不需要单独维护」,那就必须上路线③;只有出现「必须支持老客户端或特殊格式输出」时才考虑路线④。

混合架构的分工逻辑——谁做入口、谁做出口、为什么这样能兼顾稳定和成本——在机场+自建VPS混合架构指南里已经讲透,本文只接着解决它没展开的那一层:配置怎么发到所有设备,以及自建节点怎么进入订阅体系。

三、第一步:把自建节点变成「订阅源」(3X-UI 面板订阅实战)

最短路径是面板自带的订阅服务。3X-UI 的订阅服务是一个独立的 HTTP/HTTPS 服务,监听自己的端口(默认 2096),在「面板设置 → 订阅设置」里开关,路径形如 /sub/,会按客户端的 User-Agent 返回不同格式(标准节点列表 / JSON / Clash)。也就是说,面板帮你把「节点」变成了「订阅 URL」,不需要再写任何额外程序。

3.1 三个必须改的设置

  1. 启用订阅服务:订阅开关默认是关的,不勾选订阅服务根本不会启动,客户端会一直拉到 404。
  2. 订阅域名 + 端口:面板 IP 直连只能用 IP:2096 这种形式(容易被扫描、也容易在部分运营商线路上被拦截)。有域名的话,建议用 Nginx 或 Caddy 把 2096 反代到 443,订阅地址写 https://sub.你的域名/sub/xxxx。
  3. 订阅路径:必须以 / 开头和结尾,形如 /sub/,面板会自动修正格式;路径不要用 /sub、/api 这类常见词,扫路径的脚本会优先试它们。

3.2 拿到订阅链接并验证

面板里每个客户端(或按用户)都有独立的 subId,拼出来的地址就是自建节点的订阅链接。拿到后先在本机用命令行验证一次,比在客户端里试错快得多:

# 模拟 Clash 系客户端请求订阅(UA 决定返回格式)
curl -sL -A "clash-verge/v2.0" --max-time 15 -o /tmp/sub.txt -w "http_code=%{http_code}\n" \
  "https://sub.example.com:2096/sub/xxxxxxxx"

# 看看返回里有多少个节点(base64 或 yaml 都能数出协议头)
grep -c "://" /tmp/sub.txt
head -c 300 /tmp/sub.txt

返回 200 且能数出节点,说明订阅源是通的;返回 404 大概率是订阅服务没启用或路径写错,返回 000 是端口/防火墙/反代的问题。这一步验通再往下走,可以省掉后面在客户端里反复排查的时间。3X-UI 的安装、面板运维与多协议节点创建写在X-UI 面板完全指南里,这一节只取其中的订阅部分。

3.3 安全与兜底:订阅链接就是钥匙

自建订阅 URL 里带 subId,谁拿到谁就能用你的节点和流量。三条纪律:不要贴群里、不要提交进 Git 仓库、不要写进 Docker 镜像;一旦怀疑外泄,直接在面板里重置 subId,旧链接立刻失效。另外面板本身、或者承载面板的服务器挂了,订阅就拉不到了,所以本地要保留一份节点快照(第四节里的 local-snapshot 就是干这个的),这是自建订阅化唯一需要额外维护的东西。

四、Clash 侧实战:一份配置同时吃「自建订阅」和「机场订阅」

mihomo(Clash Meta)内核的 proxy-providers 是这套方案的核心:它可以把远程订阅当成一个动态节点池,并且支持健康检查。把机场订阅和面板订阅并列放进去,自建节点就和机场节点同级了。

4.1 三个 provider:机场、自建、本地快照

proxy-providers:
  # ① 机场订阅:远程,自动更新
  airport-1:
    type: http
    url: "https://机场订阅域名/api/v1/client/subscribe?token=xxxxx"
    interval: 21600          # 6 小时拉一次,够用且不给订阅端添压力
    path: ./providers/airport-1.yaml
    health-check:
      enable: true
      url: http://www.gstatic.com/generate_204
      interval: 300

  # ② 自建节点:面板订阅地址(3X-UI 的订阅服务)
  self-vps:
    type: http
    url: "https://sub.example.com:2096/sub/xxxxxxxx"
    interval: 21600
    path: ./providers/self-vps.yaml
    health-check:
      enable: true
      url: http://www.gstatic.com/generate_204
      interval: 300

  # ③ 本地快照:面板或服务器不可用时的兜底节点池
  local-snapshot:
    type: file
    path: ./providers/snapshot.yaml

4.2 策略组:让自建优先、机场兜底

proxy-groups:
  # 自建优先:自建节点全挂才切机场,适合固定出口 IP 的场景
  - name: 自建优先
    type: fallback
    use: [self-vps, airport-1]

  # 混合自动:自建与机场一起测速,谁快用谁
  - name: 混合自动
    type: url-test
    use: [airport-1, self-vps]
    url: http://www.gstatic.com/generate_204
    interval: 300
    tolerance: 80              # 容忍抖动,避免节点反复跳票

  # 只看自建:剔除面板订阅里的信息占位节点
  - name: 只看自建
    type: url-test
    use: [self-vps, local-snapshot]
    exclude-filter: "剩余流量|到期时间|官网|订阅"

语法细节(策略组类型、规则优先级、订阅更新时机)可以参考Clash Verge Rev 从入门到精通,上面这段只给能直接跑的最小骨架。有一点要提前注意:两个 provider 里的节点名如果一样,策略组解析会串线——机场节点常带城市和序号,自建节点常带 IP 或入站备注,统一在名称前加 [自建]、[机场] 前缀最省事,第六节的 Sub-Store 脚本可以批量做这件事。

把一份配置铺到所有设备之后,机场侧的设备数额度会立刻变成硬约束:电脑、手机、平板、软路由、NAS 各占一个名额,超额设备会被挤下线。自建节点不占额度,但它的瓶颈在单机带宽和 IP 寿命,线路抖动时还是得靠机场节点兜底。万达云 的 150G 全中转档是 5 台设备、300G 全专线档是 10 台设备(月付 ¥16.8 / ¥28.8),统一订阅里最实用的搭配是「自建做主力、机场做兜底」,设备数按实际终端数量选档就够,不必为闲置名额买单。

五、sing-box 侧:为什么不能照搬 Clash 的订阅方式

sing-box 的设计模型是「一份完整配置文件」:出站(outbounds)写在配置里,官方没有提供 Clash 那种把远程订阅当动态节点池的 proxy-provider 字段。所以自建节点在 sing-box 侧只有一种可靠做法:让转换器把「机场订阅 + 自建节点」合并输出成一份 sing-box JSON,节点变化时重新生成配置并重启内核。

{
  "outbounds": [
    { "type": "selector", "tag": "proxy",
      "outbounds": ["自建-东京", "自建-新加坡", "机场节点组", "auto"] },
    { "type": "urltest", "tag": "auto",
      "outbounds": ["自建-东京", "自建-新加坡", "机场节点组"],
      "url": "http://www.gstatic.com/generate_204",
      "interval": "5m", "tolerance": 100 },
    { "type": "selector", "tag": "机场节点组",
      "outbounds": ["机场节点A", "机场节点B"] },
    { "type": "vless", "tag": "自建-东京",
      "server": "203.0.113.10", "server_port": 443,
      "uuid": "00000000-0000-0000-0000-000000000000",
      "flow": "xtls-rprx-vision",
      "tls": { "enabled": true, "server_name": "www.example.com",
               "utls": { "enabled": true, "fingerprint": "chrome" } } },
    { "type": "direct", "tag": "direct" }
  ],
  "route": { "final": "proxy" }
}

三个容易踩的点:① Clash 的 YAML 订阅不能直接喂给 sing-box,必须转换,否则启动时报配置解析错误;② 混用 selector 和 urltest 时,urltest 里的节点名必须和 outbound 的 tag 完全一致,中文、空格、大小写都算不同;③ 机场节点变化后配置需要重新生成,这是 sing-box 路线的固有成本,用 Sub-Store 定时输出 + 脚本替换配置文件可以自动化。

六、Sub-Store 编排:把两个订阅合成一份,多端才算真同步

前面的方案里,机场订阅和自建订阅仍然是两个源,客户端要分别导入。要让「一处维护、多端同步」成立,中间需要一层编排,Sub-Store 是目前最省事的工具。

6.1 组合订阅:两个源,一份输出

  1. 在 Sub-Store 里新建一个组合订阅(组合 / Combine),来源填两条:机场订阅 URL、3X-UI 的自建订阅 URL。
  2. 对组合结果挂一个节点操作:批量重命名(前缀 [自建]/[机场])、去掉信息占位节点、按地区排序。
  3. 输出选 Clash(给 mihomo / OpenClash / Clash Verge Rev)或 通用 base64(给 Shadowrocket、v2rayN 这类客户端),sing-box 用户则输出 sing-box 格式。
  4. 把这一条输出 URL 发给所有设备,此后只维护这一个地址。

Sub-Store 的部署与订阅转换基础操作写在订阅转换与 Sub-Store 完全指南里,这一节接着往下讲自建节点怎么进来。真机部署位置有四种选择:本机 Docker(只给自己用最省事)、VPS(多设备外网访问)、软路由(家里设备走内网、延迟最低)、Worker 版(无服务器,但功能受运行环境限制)。订阅内容里包含自建节点参数,所以自托管比公共转换站更安全。

编排层能解决「节点太多挑花眼」,但前提是机场侧线路本身要稳,否则脚本再聪明也只是在一堆抖动的节点里挑抖动。SS-ID 的套餐清一色 IEPL 专线、节点数量不堆,适合放进统一订阅里当「设好就不动的主力 provider」:不需要额外的过滤和延迟排序规则,加上一条组合订阅就够用,月付 ¥20 起的 100G 档就是它的入门位。

七、分工:哪些流量交给自建,哪些交给机场

统一订阅之后,下一个问题是「谁走哪条链」。纯按速度选是错的,因为自建和机场的能力边界不同:自建强在出口 IP 稳定、带宽独占、不限设备;机场强在节点多、地区全、有现成的流媒体解锁和原生 IP 资源。

场景建议走哪条链原因
API 白名单、后台登录、账号操作自建(固定出口)出口 IP 不变,不容易触发异地登录风控
大文件下载、PT 做种、批量同步自建(可选叠加国内中转)不限流量、独占带宽,机场套餐容易被跑空
4K 流媒体、地区限定内容机场多地区节点齐全,解锁维护是机场的日常工作
跨境多账号、平台风控敏感业务机场住宅 / 原生 IP机房 IP 段辨识度高,住宅 IP 更接近真实用户
出门在外、临时应急机场节点多,挂了换一个,不需要回到面板操作
低延迟游戏看线路,不看自建或机场关键是物理路径,多绕一次中转就多 30ms 起

自建的短板恰好是机场的长板:机房 IP 段在流媒体和平台风控眼里辨识度太高,而住宅 IP、原生 IP 是自建 VPS 买不到的资源。仙路湾 就是按这个定位做的:¥9.9 起的普通会员是原生 IP,¥30 起的铂金会员是住宅 IP,放进统一订阅后它和自建节点同在一个策略组里,按规则各管一段流量,不需要在设备上来回切。策略组的负载均衡、自动切换与故障转移参数参考多机场订阅管理与策略组高级配置,这里不重复。

八、多端分发:一份订阅,五种接法

「一份输出发给所有端」听起来简单,实际各端的差异集中在三件事上:支持的格式、订阅更新间隔、以及本机资源。下表是常见端的接法:

端用什么接发什么格式注意
Windows / macOSClash Verge Rev(mihomo 内核)Clash YAML 订阅 URL直接在订阅页填 URL,支持定时更新
软路由OpenClash(订阅地址指向 Sub-Store 输出)Clash YAML 订阅 URL更新间隔别设太短,路由内存和订阅端都吃不消
iOSShadowrocket / Stash通用 base64 或对应格式格式不对会提示解析失败,让 Sub-Store 多输出一条
AndroidClash Meta for Android / sing-boxClash YAML 或 sing-box JSONsing-box 客户端要 JSON,配置需重新生成
NAS / 容器mihomo 容器挂载 providerClash YAML 订阅 URL + 本地快照容器里挂一份 snapshot 目录,面板挂了也不至于全断

一个实践经验:软路由是统一订阅里最值得优先接的一端。它在内网位置最好、常开、离线设备也共享它的出口;把订阅拉取放在路由上,其他设备即使只装一个指向路由的客户端也能用上自建节点,等于把「多端维护」压缩成「维护一台路由」。

九、维护与兜底:换 IP、掉线、订阅失效怎么处理

9.1 自建节点换 IP 只有一步

统一订阅化最大的收益在这里:VPS 换 IP 或改端口时,只需要在面板里改一次,订阅 URL 内容随之变化,各端下一次自动更新就拿到新节点。没有统一订阅的年代,这一步要在每台设备上重做;现在只有在「改了订阅服务本身的端口或域名」时才需要动客户端设置。

9.2 自动切换的边界

健康检查 + fallback 能在秒级把流量从挂掉的自建节点切到机场节点,但要理解两个边界:① 它只判断「节点连不连得上」,不判断线路质量,晚高峰集体降速时不会自动换;② 已建立的长连接不会立刻迁移,正在下载的任务、正在开着的视频还是走旧节点,需要重连才生效。

9.3 订阅可用性巡检

订阅拉不到,客户端是「静默失败」的:节点还在用旧的,直到全部失效才发现。放一条定时巡检脚本在任意一台常开设备上,能提前发现:

URL="https://sub.example.com:2096/sub/xxxxxxxx"
code=$(curl -s -o /tmp/sub.txt -w "%{http_code}" -A "clash-verge/v2.0" --max-time 15 "$URL")
nodes=$(grep -c "://" /tmp/sub.txt 2>/dev/null || echo 0)
if [ "$code" != "200" ] || [ "$nodes" -lt 1 ]; then
  echo "[$(date '+%F %T')] 订阅异常 http=$code nodes=$nodes" >> ~/sub-watch.log
fi

按 crontab -e 加一条每天执行即可。另外建议保留「上一版可用配置」:Sub-Store 输出里留一份本地快照、客户端配置目录定期备份,出问题时能立刻回滚,比现场排查快得多。更新间隔上,常开设备 4 到 6 小时一次足够,路由和 NAS 别低于 1 小时。

十、十个高频坑(含排查方向)

现象根因处理
策略组里节点混在一起、切了没反应两个 provider 节点重名,解析串线加 [自建]/[机场] 前缀,或用 filter
节点莫名多出「剩余流量 xx」面板订阅里的信息占位节点用 exclude-filter 排除关键词
订阅地址被扫、流量被蹭subId 外泄 / 路径太好猜重置 subId,路径改复杂并走 HTTPS 反代
客户端提示解析失败格式不匹配(YAML 喂给 sing-box、JSON 喂给 Clash)在 Sub-Store 里多输出一条对应格式
节点延迟正常但视频卡自建节点没放行 UDP / QUIC服务端与防火墙同时放行 UDP
软路由变卡、面板被频繁访问provider 更新间隔过短路由端间隔调到 4-6 小时
某个设备被挤下线统一订阅铺开后撞上机场设备数上限按终端数量重新选档,或让无关设备只走自建
切换总在抖动、频繁跳票tolerance 太小,节点延迟微抖就重选调到 50-100ms,并拉长测试间隔
面板正常但订阅 404订阅服务没启用 / 路径写错检查开关与 /sub/ 路径,用 curl 验证
自建节点集体失效IP 被墙 / 机房线路调整面板换 IP 后各端自动同步;期间由机场兜底

十一、决策框架:三类用户的推荐配置

你的情况推荐路线具体做法
只有机场订阅,2-3 台设备不做统一订阅各端直接导机场订阅,别增加中间层,维护成本高于收益
1-2 台 VPS + 3 台以上设备,想要省心路线② + ③面板开订阅服务 → Sub-Store 组合「自建 + 机场」→ 输出一个 URL 给所有端
多台 VPS / 多协议 / 有软路由和 NAS路线③(+ ④)Sub-Store 编排 + 节点命名规范 + 快照兜底;老客户端多时再上自建 subconverter

不建议的情形也说清楚:只有一台 VPS、两台设备,或者完全不打算维护面板的人,统一订阅化是净增负担。这种情况下直接用现成的机场订阅,把「节点运维」这层外包出去,才是成本最低的选择。

十二、常见问题(FAQ)

Q1:自建节点和机场节点放进同一个策略组,会互相影响吗?

不会互相污染,它们只是同一个策略组里的候选节点。要注意的是「谁被选中」:url-test 按延迟选,通常自建胜出(少一跳);fallback 按顺序选,写在前面的优先;load-balance 会同时使用多个节点,这时出口 IP 会漂移,固定 IP 场景不要用。

Q2:机场订阅和自建订阅能放进同一个 provider 列表吗?

可以,mihomo 允许在同一策略组里使用多个 provider。但两个 provider 的节点命名规则不同,建议先用 Sub-Store 统一改名再输出,比在配置里写复杂正则更省事。

Q3:Sub-Store 必须部署在 VPS 上吗?

不必。只给自己用,本机 Docker 部署最省事;家里设备多、都走内网,软路由上跑延迟最低;需要在外网访问才考虑 VPS;Worker 版适合不想维护服务器的人,但功能受运行环境限制。唯一的要求是「常开」。

Q4:一份订阅能给几台设备用?

自建节点不受设备数限制,限制来自机场侧套餐:机场订阅本身会统计同时在线设备数。统一订阅不会绕过这个限制,反而更容易撞上,因为所有端都在拉同一份配置。选档时按实际终端数量来,别按「可能用到的设备」来。

Q5:自建节点被墙了,会自动切到机场吗?

用 fallback 策略组、自建写在前面时会自动切,切换时机取决于健康检查间隔(通常 300 秒内)。用 url-test 时也会切,但它是按延迟排序,被墙节点延迟会飙升从而被淘汰,效果类似。两种都只解决「连不上」,不解决「慢」。

Q6:3X-UI 的订阅链接能直接给 Clash 用吗?

大多数情况可以,面板会按 User-Agent 返回 Clash 格式。如果客户端拿到的是 base64 节点列表而不是 YAML,用 Sub-Store 转一手即可,这也是把自建订阅放进组合订阅的原因之一。

Q7:sing-box 能直接吃 Clash 订阅吗?

不能。sing-box 用的是自己的 JSON 配置结构,Clash 订阅必须转换。主流做法是让 Sub-Store 或转换器直接输出 sing-box 格式,再替换本机配置文件并重启内核。

Q8:订阅多久更新一次合适?

常开设备 4-6 小时一次已经足够,节点变化通常在分钟级就同步完成;路由和 NAS 不低于 1 小时,避免资源占用和订阅端压力。节点被墙这类突发情况,靠健康检查兜底,不靠缩短更新间隔。

Q9:统一订阅之后还需要 TUN 模式吗?

两者不冲突。统一订阅解决「节点从哪来、怎么同步」,TUN 解决「哪些程序走代理」。需要接管所有程序(含不读系统代理的软件、游戏、Docker 容器)时开 TUN;只需要浏览器走代理时用系统代理就够。

Q10:不想维护面板,还有必要做统一订阅吗?

没有必要。统一订阅的价值建立在「有自建节点要维护」之上;没有自建节点,直接用机场订阅就是最省心的形态。反过来,如果自建只是偶尔用,也可以把自建节点留在本地客户端里,不纳入订阅体系。

Q11:把订阅链接放进 Git 仓库或 Docker 镜像有什么风险?

等于把节点和流量公开送人。自建订阅泄露会导致别人消耗你的 VPS 流量、甚至因异常流量被服务商封号。用环境变量或本地配置文件保存,仓库里放模板(providers/example.yaml)和 .gitignore 规则,是更稳的工程习惯。

Q12:这套方案能不能用于团队?

可以,结构不变,只是把 Sub-Store 放到团队服务器、给每人输出不同订阅(各自带自己的 token),并约定节点命名规范。团队场景要额外注意两点:设备数额度按人头算,以及订阅输出的访问控制,别让一份 URL 在内部群里无限扩散。

把这套流程走完,你会得到一条固定的输出地址:自建节点在面板里维护、机场订阅在后台维护、所有设备只认这一条链接。节点运维从「每台设备都要记得改」变成「改一次,等它自己同步」,这才是统一订阅化真正的收益。

推荐阅读