自建节点的日常大概是这样:新买一台 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 三个必须改的设置
- 启用订阅服务:订阅开关默认是关的,不勾选订阅服务根本不会启动,客户端会一直拉到 404。
- 订阅域名 + 端口:面板 IP 直连只能用 IP:2096 这种形式(容易被扫描、也容易在部分运营商线路上被拦截)。有域名的话,建议用 Nginx 或 Caddy 把 2096 反代到 443,订阅地址写
https://sub.你的域名/sub/xxxx。 - 订阅路径:必须以
/开头和结尾,形如/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 组合订阅:两个源,一份输出
- 在 Sub-Store 里新建一个组合订阅(组合 / Combine),来源填两条:机场订阅 URL、3X-UI 的自建订阅 URL。
- 对组合结果挂一个节点操作:批量重命名(前缀
[自建]/[机场])、去掉信息占位节点、按地区排序。 - 输出选 Clash(给 mihomo / OpenClash / Clash Verge Rev)或 通用 base64(给 Shadowrocket、v2rayN 这类客户端),sing-box 用户则输出 sing-box 格式。
- 把这一条输出 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 / macOS | Clash Verge Rev(mihomo 内核) | Clash YAML 订阅 URL | 直接在订阅页填 URL,支持定时更新 |
| 软路由 | OpenClash(订阅地址指向 Sub-Store 输出) | Clash YAML 订阅 URL | 更新间隔别设太短,路由内存和订阅端都吃不消 |
| iOS | Shadowrocket / Stash | 通用 base64 或对应格式 | 格式不对会提示解析失败,让 Sub-Store 多输出一条 |
| Android | Clash Meta for Android / sing-box | Clash YAML 或 sing-box JSON | sing-box 客户端要 JSON,配置需重新生成 |
| NAS / 容器 | mihomo 容器挂载 provider | Clash 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 在内部群里无限扩散。
把这套流程走完,你会得到一条固定的输出地址:自建节点在面板里维护、机场订阅在后台维护、所有设备只认这一条链接。节点运维从「每台设备都要记得改」变成「改一次,等它自己同步」,这才是统一订阅化真正的收益。