Star 历史趋势
数据来源: GitHub API · 生成自 Stargazers.cn
README.md

Sub-Store Workers

Sub-Store Workers

Sub-Store 后端的 Cloudflare Workers 移植版

Deploy to Cloudflare

Project Overview

注意:一键部署按钮仅供参考,由于项目需要本地构建(esbuild + Sub-Store 源码),实际无法直接通过此按钮完成部署。请参照下方手动部署步骤

自动部署:本仓库已内置 GitHub Actions 工作流,每天自动检测上游 Sub-Store 更新并部署到 Cloudflare。只需配置 Secrets 即可开启,无需本地操作。详见 GitHub Actions 自动同步上游

简介

Sub-Store 后端部署到 Cloudflare Workers / Pages,无需服务器,免费使用。

  • 零服务器:运行在 Cloudflare 边缘网络
  • KV 持久化:数据存储在 Cloudflare KV
  • 完整功能:复用原始后端全部业务逻辑(订阅管理、格式转换、下载、预览等)
  • 预编译解析器:peggy 文法在构建时编译,避免运行时 eval()

目录

架构说明(如果你只想部署可跳过)
sub-store-workers/src/        ← Workers 适配层(6 个文件)
Sub-Store/backend/src/        ← 原始后端源码(直接复用)
esbuild.js                    ← 构建脚本,通过插件桥接两者

仅替换了平台相关层,核心逻辑零修改:

Workers 文件作用
vendor/open-api.jsKV 替换 fs,fetch 替换 undici
vendor/express.jsWorkers fetch handler 替换 Node express
core/app.js导入 Workers 版 OpenAPI
utils/env.js环境检测
restful/token.js允许 Workers 签发 token
index.jsWorkers 入口

更详细的项目总图见 mydocs/codemap/project-overview.md

部署

部署总览:1.准备 → 2.上传 Workers/Pages → 3.设密码(必做)→ 4.连接前端

为什么两个都要部?*.workers.dev 在国内被 GFW 封锁,*.pages.dev 走 Cloudflare CDN 通常可直连。

  • 有自定义域名:只用 Workers 即可
  • 无自定义域名:Pages 对外提供 API,Workers 在后台跑 Cron。

1. 克隆仓库

# 目录结构必须如下:
# parent/
#   ├── Sub-Store/          ← 原始后端源码
#   └── sub-store-workers/  ← 本项目

git clone https://github.com/sub-store-org/Sub-Store.git
git clone https://github.com/Yu9191/sub-store-workers.git

cd sub-store-workers
npm install

2. 登录 Cloudflare

npx wrangler login

3. 创建 KV 命名空间

npx wrangler kv namespace create SUB_STORE_DATA

将返回的 id 填入 wrangler.toml

[[kv_namespaces]]
binding = "SUB_STORE_DATA"
id = "你的KV命名空间ID"

4. 构建 & 部署

两者都需要部署:

部署方式域名用途
Workers*.workers.dev 或自定义域名API + Cron 定时同步
Pages*.pages.devAPI(国内可直连)

⚠️ 执行下方部署命令前,请先确认已完成「1. 克隆仓库」「2. 登录 Cloudflare」「3. 创建 KV 命名空间」三步,并完整阅读下文「5. 连接前端」「6. API 鉴权」两节。部署完未设密码前 Worker 是公开的,任何人都能管理你的数据。

# Workers 部署(含 Cron Triggers)
npm run deploy

# Pages 部署(国内可用,一条命令)
npm run deploy:pages

强烈建议部署后立即设置鉴权密码,否则任何人都能管理你的 Sub-Store 数据:

# Windows
npm run rotate-secret

# Linux / macOS
npm run rotate-secret:sh

脚本会生成随机 URL-safe 密码,写入 Cloudflare Worker Secret,并复制到剪贴板。详细说明见下文“6. API 鉴权”。

Pages 部署完成后还需要在 Cloudflare Dashboard 中:

  1. 绑定 KV 命名空间 SUB_STORE_DATA
  2. 设置鉴权密码 Secret SUB_STORE_FRONTEND_BACKEND_PATH

详细图文步骤见下文 6. API 鉴权 → 方式 A.2 Pages 端。配置完成后必须再跑一次 npm run deploy:pages 让绑定生效。

自定义域名注意事项(如果你绑定了自有域名)
  • SSL/TLS 加密模式必须设为 Full(Cloudflare Dashboard → 域名 → SSL/TLS → 概述)
  • Cloudflare 免费 SSL 证书只覆盖一级子域名*.example.com),不支持多级子域名(如 a.b.example.com
    • 正确 substore.example.com
    • 错误 substore.sub.example.com(会导致 ERR_CONNECTION_CLOSED

5. 连接前端

打开 Sub-Store 前端,后端地址格式:

你的域名/你的密码

例如:

https://sub-store-workers.your.workers.dev/aBc123XyZ
https://sub-store.your.pages.dev/aBc123XyZ

注意:末尾的 /密码 不能省略,否则 /api/... 会全部 401。

部署完后访问 https://你的域名/你的密码/api/utils/worker-status,应返回:

{ "kv": { "bound": true }, "auth": { "backendPathConfigured": true } }

6. API 鉴权(强烈建议 / 已在第 4 步完成可跳过)

默认 API 无密码保护。不设密码任何人都能管理你的订阅。第 4 步执行 npm run rotate-secret 已经设过的话,可以跳过本节。

推荐使用 Worker / Pages Secret(加密存储)。不要写到 wrangler.toml [vars] 里——那里是明文,会随 commit 泄漏,并且 wrangler deploy 会用它覆盖同名 Secret,与下面的流程冲突。

方式 A(推荐):使用 Cloudflare Secret

A.1 Workers 端(项目自带脚本)

仓库提供了密钥轮换脚本,一行命令完成生成 + 写入 + 复制到剪贴板:

# Windows
npm run rotate-secret

# Linux / macOS
npm run rotate-secret:sh

脚本会:

  • 用加密随机数生成 32 位 URL-safe 密码
  • 自动加 / 前缀
  • 通过管道写入 Cloudflare Worker Secret SUB_STORE_FRONTEND_BACKEND_PATH(密码不落盘、不显示在屏幕、不进入 shell 历史)
  • 复制到剪贴板,方便粘贴到前端配置

执行成功后,请同步更新:

  1. 前端后端地址:https://xxx.workers.dev<剪贴板里的新密码>
  2. 如果使用 GitHub Actions 自动部署,还要更新仓库 Secret(如 SUB_STORE_PASSWORD_VALUE

用完后建议清空剪贴板:

  • PowerShell:Set-Clipboard -Value $null
  • macOS:pbcopy </dev/null
  • Linux:wl-copy --clearxsel --clipboard --clear

也可以手动设置(提示输入时填带 / 开头的密码):

npx wrangler secret put SUB_STORE_FRONTEND_BACKEND_PATH
A.2 Pages 端(在 Dashboard 配置)

wrangler.toml[[kv_namespaces]][vars] 只对 Workers 生效。Pages 项目必须在 Cloudflare Dashboard 单独绑定 KV 与设置密码,否则 API 会因为缺少 KV 而 500,且任何人都可访问管理 API。

① 进入 Workers & Pages,点击 sub-store 项目

进入项目

② 进入 设置 → 绑定,点击 + 添加 KV 命名空间

添加绑定

③ 选择 KV 命名空间

选择 KV

④ 变量名填 SUB_STORE_DATA,选择对应 KV,保存

保存绑定

⑤ 进入 设置 → 变量和机密,点击 + 添加

添加变量

⑥ 变量名填 SUB_STORE_FRONTEND_BACKEND_PATH,值填 /你的密码(必须带 / 开头),类型选 Secret(加密),保存

填写变量

保存后必须重新部署 npm run deploy:pages 才能生效。

Pages 不能跨项目共享 Worker Secret,建议把 Workers 与 Pages 的 SUB_STORE_FRONTEND_BACKEND_PATH 设为同一个值,方便前端切换。

方式 B(不推荐):使用 wrangler.toml [vars] 明文变量

[vars]
SUB_STORE_FRONTEND_BACKEND_PATH = "/你的密码"

仅在临时调试时使用。明文写仓库文件容易随 commit 泄漏;同时 wrangler deploy 会用它覆盖 Secret,破坏方式 A 的 CI/Secret 流程。生产环境请使用方式 A。

分享链接(download/preview)不受鉴权影响,无需密码即可访问。

分享按钮:订阅列表里的“分享”按钮仅在通过密码前缀访问时显示(与上游 Docker/Node 部署的 be_merge 行为一致),未配置密码前缀的部署不会显示分享按钮。


进阶配置 / 平台说明

本地开发
npm run dev

访问 http://127.0.0.1:3000

推送通知(Bark / Pushover)

支持 HTTP URL 推送方式。在 wrangler.toml 中配置:

[vars]
SUB_STORE_PUSH_SERVICE = "https://api.day.app/你的BarkKey/[推送标题]/[推送内容]"

Pages 需要在 Dashboard 手动添加同名环境变量。不支持 shoutrrr(命令行工具)。

环境变量一览
变量说明必填
SUB_STORE_FRONTEND_BACKEND_PATHAPI 路径前缀密码,推荐用 Worker Secret 管理否(生产环境必设)
SUB_STORE_PUSH_SERVICEHTTP URL 推送地址
SCRIPT_ENGINE默认启用 QuickJS WASM 沙箱执行 Script Operator;设为 disabled 可关闭
状态检查接口 / Script Operator 限制
https://你的域名/你的密码/api/utils/worker-status

返回字段说明:

  • kv.bound:是否已正确绑定 KV
  • auth.backendPathConfigured:是否已配置鉴权
  • auth.managementApiPublic:管理 API 是否处于公开状态
  • capabilities:当前部署支持/不支持的能力(脚本操作、Gist 备份、Cron 等)

脚本操作(Script Operator):Cloudflare Workers 禁止 eval / new Function,本仓库通过 QuickJS WASM 沙箱执行 Script Operator,默认启用,无需额外配置。如需关闭,可在 wrangler.toml [vars] 设置 SCRIPT_ENGINE = "disabled"

esbuild 插件
插件作用
路径别名解析解析 @/ 导入,优先 Workers 覆盖
eval 重写将 eval() 调用替换为静态表达式
peggy 预编译构建时编译 PEG 文法,消除运行时 eval
Node 模块存根存根 fs/crypto 等不可用模块
Cron 定时同步

Workers 版内置了 Cron Trigger,默认每天 23:55(北京时间) 自动同步 artifacts 到 Gist。

可在 wrangler.toml 修改频率:

[triggers]
crons = ["55 15 * * *"]  # UTC 时间,+8 即北京时间

前提:在前端 Settings 中配置好 GitHub 用户名和 Gist Token。

KV 读写优化

Cloudflare KV 免费额度:读 10 万次/天,写 1000 次/天

本项目已实现两层优化:

  • 脏标记:仅在调用 $.write() / $.delete() 时标记脏位,纯读请求不触发写入
  • 内容对比:写入前将当前数据与加载时的快照对比,内容相同则跳过写入(防止 $.write() 写回相同数据)
  • 边缘缓存:KV 读取设置 60 秒 cacheTtl,短时间内多次请求命中边缘缓存,不计入 KV 读次数
操作KV 读KV 写
打开前端浏览数据(~8 个请求)1 次(其余命中缓存)0 次
修改订阅/设置0~1 次1 次
Cron 定时同步1 次1 次

个人使用完全不用担心超额。

Workers 平台限制 / 不支持的功能

平台限制

限制说明
请求超时 30 秒单次请求墙钟时间上限 30 秒,订阅源响应慢会超时失败
出站 IP 为境外从 Cloudflare 节点拉取订阅,部分限制国内 IP 的订阅源无法拉取
推送通知仅支持 HTTP URL 方式(Bark、Pushover 等),不支持 shoutrrr

如果你的订阅源限制国内访问或响应较慢,建议使用 VPS 自建 Node.js 版本。

Node 专属功能(Workers 无法实现)

功能原因
前端静态文件托管需要 express.static + fs,无本地文件系统
前端代理中间件需要 http-proxy-middleware,Node 专属
MMDB IP 查询需要读取本地 MMDB 文件(@maxmind/geoip2-node
MMDB 定时下载需要 fs.writeFile 写入本地文件
DATA_URL 启动恢复需要 Node fs 写文件
Gist 备份定时下载从 Gist 下载恢复备份的 Cron(手动触发仍可用)
ip-flag-node.js 脚本依赖本地 MMDB,可用 ip-flag.js(HTTP API)替代
jsrsasign TLS 指纹全局作用域限制
shoutrrr 推送需要 child_process 执行命令行工具
代理请求Workers 出站走 Cloudflare 网络,不支持自定义 HTTP/SOCKS5 代理

FAQ

常见问题

Q: 前端提示 找不到 Sub-Store Artifacts Repository A: 正常现象,你还没创建同步配置。创建第一个同步后会自动生成。

Q: 拉取订阅超时 A: Workers 单次请求上限 30 秒。如果订阅源响应慢,会超时失败。可尝试换一个订阅链接。

Q: 某些订阅源返回空或报错 A: Workers 出站 IP 为境外 Cloudflare 节点,部分限制国内 IP 的订阅源无法拉取。

Q: 如何更新到最新版? A: 见下方「同步更新」章节。

Q: 忘了设置的密码怎么办? A: Worker Secret 在 Dashboard 看不到原文,无法找回。直接 npm run rotate-secret 重置即可。


同步更新

更新 sub-store-workers(本项目)
cd sub-store-workers
git pull
npm run deploy

Worker Secret 不会被 deploy 覆盖,密码保持不变。

更新 Sub-Store 原始仓库

当原始仓库有新版本时,手动执行:

cd Sub-Store
git pull

cd ../sub-store-workers
npm run deploy

esbuild 构建时会从 Sub-Store/backend/src/ 读取最新源码,重新 build 即可包含新功能。

GitHub Actions 自动同步上游(推荐)

仓库内置了 .github/workflows/sync-upstream.yml 工作流,每天自动检测 Sub-Store 上游更新并部署。QuickJS Script Operator 默认启用,同时工作流会自动通过 Cloudflare API 为 Pages 项目设置 SCRIPT_ENGINE 环境变量,无需手动配置。

工作流程

每天 00:00(北京时间)自动触发
  ↓
拉取上游最新 commit,对比已部署版本
  ↓ 有更新
安装依赖 → 运行上游测试套件
  ↓ 测试通过
构建 → 部署 Workers → 部署 Pages → 健康检查
  ↓ 全部成功
记录已部署版本 + Bark 通知

任何环节失败 → Bark 通知"同步失败",线上版本不受影响

配置步骤

1. 创建 Cloudflare API Token

打开 Cloudflare API Tokens → Create Token → Custom Token,添加以下权限:

资源权限级别
Account → Workers 脚本编辑你的账号
Account → Cloudflare Pages编辑你的账号
Account → Workers KV 存储编辑你的账号
User → 用户详细信息读取--

Account Resources 选择 Include → 你的账号

2. 添加 GitHub Repository Secrets

打开仓库 Settings → Secrets and variables → Actions → New repository secret,依次添加:

Secret 名称说明
CLOUDFLARE_API_TOKEN上一步创建的 TokenCloudflare 部署认证
CLOUDFLARE_ACCOUNT_ID你的 Account IDCloudflare Dashboard 首页右侧可见
KV_NAMESPACE_IDKV 命名空间 ID创建 KV 时返回的 id
PAGES_PROJECT_NAMEPages 项目名例如 sub-store
WORKERS_SUBDOMAINWorkers 子域名例如 sub-store2(即 *.sub-store2.workers.dev 中的部分)
BARK_KEYBark 推送 Key可选,用于成功/失败通知

3. 手动触发验证

打开仓库 Actions 页面 → Sync Upstream Sub-Store → Run workflow → 勾选 force = true → Run。

全部绿色即配置成功,之后每天自动运行。

风险与失败场景

场景后果处理方式
上游测试未通过不会部署,线上不受影响等上游修复后下次自动重试
构建失败(上游引入了 Workers 不兼容的 API)不会部署需要手动适配 src/ 覆盖层,提 issue
Cloudflare API 超时/限流部署中断下次自动重试
API Token 过期或权限不足部署失败重新创建 Token 并更新 GitHub Secret
上游大版本重构(目录结构变化)构建失败需要手动更新 esbuild 配置
健康检查失败Workers/Pages 已部署但版本标记不更新手动检查线上是否正常

安全提示:Cloudflare API Token 和 Account ID 请通过 GitHub Secrets 管理,不要写入任何文件或提交到仓库。

手动触发:任何时候都可以在 Actions 页面手动 Run workflow,force = true 会跳过版本检查强制部署。


Surge 面板脚本

展开查看

surge/ 目录下提供了一个 Surge Panel 脚本,可在 Surge 面板中实时监控 Cloudflare Workers 用量。

功能

  • Workers / Pages 请求次数及占比
  • KV 读写次数
  • Sub-Store 订阅数量、后端版本(可选)
  • 中英文切换

使用方式

在 Surge 中安装模块:

https://raw.githubusercontent.com/Yu9191/sub-store-workers/main/surge/SubStorePanel.sgmodule

安装后编辑模块参数填入:

参数说明
IDCloudflare Account ID
TokenCloudflare API Token
Limit每日请求额度,默认 100000
SubStoreURLSub-Store 后端地址(可选,如 https://example.com/your-path
Lang语言,encn,默认 en

API Token 权限

Cloudflare API Tokens 页面创建 Custom Token,只需开启 1 个权限

权限级别
Account AnalyticsRead

建议过期时间选「无过期时间」。


致谢

基于 Sub-Store 项目,感谢原作者及所有贡献者。

QuickJS WASM Script Operator 适配来自用户 PR,贡献者:0xPoker

许可证

GPL V3

关于 About

Sub-Store 后端 Cloudflare Workers/Pages 移植版
cloudflare-pagescloudflare-workersstoresubscription

语言 Languages

JavaScript90.9%
PowerShell4.8%
Shell4.3%
HTML0.1%

提交活跃度 Commit Activity

代码提交热力图
过去 52 周的开发活跃度
114
Total Commits
峰值: 17次/周
Less
More

核心贡献者 Contributors