sub-store
sub-store订阅管理工具
sub-store
基础概念
Sub-Store 用于统一管理订阅、节点集合(Collection)和完整配置文件(File)。长期给 Nikki / Mihomo 等客户端使用时,应区分“管理后台 URL”和“公开分享 URL”。
当前采用的稳定结构:
管理后台:admin.bakersean.top/<可轮换 Backend Prefix>/...
公开分享:substore.bakersean.top/share/...
后台随机 Prefix 可以在迁移或安全加固时轮换;客户端长期订阅只使用 substore.bakersean.top/share/...,因此不随后台 Prefix 或 VPS IP 变化。
稳定 Share URL 的原理
Sub-Store 后端实际上仍运行在带随机 Prefix 的路径下,Caddy 对外提供固定 /share/*,再在服务器内部改写到当前 Prefix:
客户端
↓
https://substore.bakersean.top/share/...
↓ Caddy URI rewrite
/<CURRENT_PREFIX>/share/...
↓
Sub-Store Backend
因此迁移 VPS 或轮换后台 Prefix 时,只需要更新服务器端反代映射;Nikki / Mihomo 端无需修改订阅地址。
当前资源 URL 约定:
File: https://substore.bakersean.top/share/file/<文件名>
Collection: https://substore.bakersean.top/share/col/<集合名>/<输出格式>
Sub: https://substore.bakersean.top/share/sub/<订阅名>/<输出格式>
当前 Nikki 使用的完整主配置文件:
https://substore.bakersean.top/share/file/all-nodes-all-ways
该 File 本身就是完整 Mihomo YAML,不需要追加 ClashMeta 后缀。
当前主配置内部两个自建节点 Provider 也使用稳定 Share URL:
https://substore.bakersean.top/share/col/all-self-node-for-collect-directly/ClashMeta
https://substore.bakersean.top/share/col/all-self-node-for-land/ClashMeta
[!note] 当前取舍 暂时保持直接
/share/*结构,不再额外添加长期 Secret 路径。以后若需要增强分享链接防猜测能力,再单独增加稳定 Secret 层;不要把管理后台随机 Prefix 重新暴露给客户端。
Oracle2 当前部署与备份边界
2026-09-08 核查当前 Oracle2 生产环境后,Sub-Store 的关键状态分成三类:
/var/lib/sub-store/sub-store.json # 订阅、集合、File 等核心业务状态
/var/lib/sub-store/root.json # Sub-Store 根状态
/etc/sub-store/sub-store.env # 后端监听、Prefix、数据目录、CORS 等运行配置
/opt/cpa/Caddyfile # admin / share 稳定入口与内部路径映射
/opt/sub-store/repo/ # 可重新拉取和构建的应用代码
其中真正不可替代的是业务 JSON、运行配置和反向代理规则;/opt/sub-store/repo/ 属于可重建代码,不应被当成最核心的数据备份对象。
层 1:本机变更前回滚快照
在稳定 Share / Provider URL 迁移前,曾创建:
/opt/sub-store/backups/stable-provider-20260907T031440Z/
├── sub-store.json
├── root.json
└── Caddyfile
这个快照的设计目的是:如果把 Provider 从管理后台随机 Prefix URL 改成稳定 /share/* URL 后出现问题,可以同时回滚 Sub-Store 业务状态 + Caddy 映射,避免只恢复一边造成配置不一致。
这类 /opt/sub-store/backups/<reason>-<timestamp>/ 快照仍然保留,用于最近一次变更的快速回滚。
层 2:Oracle2 共用 OneDrive 周备份
2026-09-08 起,Sub-Store 已经接入 Oracle2 统一周备份,不再处于“只有本机快照”的状态:
oracle2-agent-backup.timer
↓
personal-infrastructure/etc/server/oracle2/backup-to-onedrive.sh
↓
myonedrive:/ServerBackups/Oracle2
归档格式:
schema=oracle2-runtime-backup-v3
components=hermes,cpa,nezha-dashboard,sub-store
Sub-Store payload 当前包含:
sub-store/
├── sub-store.json
├── root.json
├── sub-store.env
├── sub-store.service
├── Caddyfile
└── repo-commit.txt
为什么备份时短暂停服务
sub-store.json 和 root.json 是两个独立的可变文件。若服务持续写入、直接先后复制,理论上可能得到两个不同时间点的状态。因此周备份采用:
systemctl stop sub-store
↓
复制 sub-store.json + root.json + env + unit + Caddy
↓
解析两个 JSON,确认格式有效
↓
systemctl start sub-store
实际文件很小,停机窗口只覆盖复制与 JSON 校验。脚本还维护 sub_store_restart_needed cleanup 状态:如果中途失败退出,只要备份前服务原本在线,cleanup 仍会尝试重新启动 sub-store.service。
这比在不知道 Sub-Store 是否提供原生 snapshot/transaction 接口时直接复制运行中的两个 JSON 更稳妥。
为什么不备份整个源码目录
/opt/sub-store/repo/ 可以从 Git 仓库重新拉取和构建,因此周归档只记录 repo-commit.txt,用于恢复时知道应该重建哪个版本。真正需要异地保存的是:
- 业务 JSON;
- 运行 env;
- systemd unit;
- 与稳定 Share URL 绑定的 Caddy 路由。
全新 Oracle2 恢复时,应先把 Sub-Store backend 重建到对应版本,再应用持久状态。
2026-09-08 验收
真实 OneDrive 周备份:
oracle2-agent-20260908T044352Z.tar.gz
已通过 restore-drill.sh:
- archive 外层 SHA-256;
- 内层
SHA256SUMS; sub-store.json与root.jsonJSON 解析;- env、unit、Caddy 和 commit 文件存在性;
- 备份完成后
sub-store.service = active。
实现提交:
d832727 feat(backup): include Nezha and Sub-Store in Oracle2 weekly backups
[!warning] 当前安全边界 Oracle2 周归档不是客户端加密文件,而是
protection=onedrive-access-control-only的普通tar.gz。sub-store.env与其他 Oracle2 secret 一起受 OneDrive 账号权限保护,因此 Microsoft 账号 MFA、OAuth 应用审计和最小共享权限非常重要。
快速回滚思路
当一次 Sub-Store 配置变更刚刚导致订阅异常时,本机快照仍是最快路径:
- 停止
sub-store.service,避免继续写入。 - 备份当前故障状态,避免丢失现场。
- 从对应
/opt/sub-store/backups/<reason>-<timestamp>/恢复sub-store.json与root.json。 - 若该变更同时修改了稳定分享路径,再恢复同一批次的 Caddyfile。
- 启动 Sub-Store,reload Caddy。
- 验证主 File、两个自建 Provider 和管理后台。
如果是 Oracle2 整机损坏,则使用 OneDrive oracle2-runtime-backup-v3 恢复链,而不是依赖同机 /opt/sub-store/backups/。
使用指南
配置 nginx 反代
- 配置 域名的 DNS
- 生成证书
- 创建 nginx 配置文件
server {
listen 80;
server_name sub.bakersean.cloudns.ch; # 替换为您的 Sub-store 域名
# 强制将所有 HTTP 请求重定向到 HTTPS
return 301 https://$host$request_uri;
}
server {
# 监听 443 端口,启用 SSL/TLS 和 HTTP/2
listen 443 ssl http2;
server_name sub.bakersean.cloudns.ch; # 替换为您的 Sub-store 域名
# Certbot 自动生成的证书路径 (通常是这个路径,请根据实际情况核对)
ssl_certificate /etc/letsencrypt/live/sub.bakersean.cloudns.ch/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sub.bakersean.cloudns.ch/privkey.pem;
# Certbot 推荐的 SSL 参数 (保障安全)
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # 确保 Certbot 运行过一次后会生成此文件
# 反向代理设置
location / {
# 转发到 Sub-store 所在的端
proxy_pass http://127.0.x.x:3001;
# 确保后端服务能获取正确的客户端 IP 和域名信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 增加超时设置,防止连接被过早切断
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
经验总结
- 不要把
admin.bakersean.top/<随机 Prefix>/api/...当作 Nikki 的长期订阅地址;它属于管理后台/API 路径,会随安全轮换变化。 - 客户端长期订阅统一走
substore.bakersean.top/share/...。 - VPS 迁移时只要 DNS/Cloudflare 指向新服务器,并恢复同样的
/share/*反代规则,客户端 URL 可以保持不变。 - 改 Sub-Store 业务数据和 Caddy 稳定分享映射时,应在同一个带原因和时间戳的快照中保存,避免只回滚一半。
/opt/sub-store/backups/是本机快速回滚层;Oracle2 周备份是异地灾备层。- 周备份为两个 JSON 获取一致时间点时,宁可短暂停服务,也不要假设两个运行中文件随便复制就一定一致。
信息参考
GetSomeCats/Substore的云同步操作步骤.md at Surge · getsomecat/GetSomeCats
Related notes
- 相关概念: Certbot
- 部署实践: [private note]
- 备份原则: 维护与备份 OCI 服务器