Skip to content

GitHub Actions 自动部署

EdgeChat 的核心部署方式就是 GitHub Actions + Cloudflare Workers。

工作流文件在仓库的 .github/workflows/deploy-worker.yml,推送代码后就能自动完成部署。

必需配置

配置项作用
CLOUDFLARE_API_TOKEN允许 Actions 调用 Cloudflare API,创建、检查并部署资源。
CLOUDFLARE_ACCOUNT_ID指定部署目标账号。
CFCHAT_ADMIN_USERNAME首次部署时自动创建管理员用户名。
CFCHAT_ADMIN_PASSWORD首次部署时自动创建管理员密码。

可选配置

配置项作用
CFCHAT_ADMIN_DISPLAY_NAME管理员显示名称,不填时默认使用用户名。
EDGECHAT_ENCRYPTION_KEYRING可选的完整服务端加密密钥环;不配置时首次部署自动生成。

触发方式

  • 推送到 mastermain
  • 在 GitHub Actions 页面手动触发 workflow_dispatch

工作流步骤

  1. 拉取代码
  2. 安装依赖
  3. 构建前端
  4. 检查或创建 Cloudflare 资源
  5. 生成 CI 专用 wrangler.ci.toml
  6. 首次创建 D1 时初始化数据库
  7. 检查并执行尚未应用的 D1 迁移
  8. 使用随代码自动生成的 schema manifest 验证迁移记录和完整结构
  9. 可选写入管理员账号
  10. 检查并准备 Worker 加密 Secret
  11. 部署 Worker

R2 附件能力

资源检查步骤会调用 Cloudflare 官方接口 GET /accounts/{ACCOUNT_ID}/r2/buckets?per_page=1 判断目标账号是否已经开通 R2。

  • 已开通 R2:继续复用或创建 cfchat-files bucket,并按原方式建立 FILES binding
  • Cloudflare 返回错误码 10042:继续部署 Worker,但从 CI 配置中移除 FILES binding
  • Token 权限不足、账号 ID 错误或其他 Cloudflare API 异常:停止部署,避免把配置错误误判为未开通 R2

没有开通 R2 时,登录、文字聊天和后台管理仍可使用;用户上传附件时会直接看到“当前部署没有绑定 R2,无法上传附件”。附件读取和 Telegram 文件同步同样不可用。开通 R2 后重新运行 Deploy Worker,工作流会幂等创建或复用 bucket,并自动恢复附件能力。

服务端加密密钥

默认自动模式使用独立的版本化 Worker Secrets 保存每一把密钥,并用单独的 active key ID 指向新写入数据应使用的版本。已有的 EDGECHAT_ENCRYPTION_KEYRING JSON 密钥环继续兼容,手动格式为:

json
{"activeKeyId":"v1","keys":{"v1":"BASE64_ENCODED_32_BYTE_KEY"}}
  • 目标 Worker 没有加密 Secret 时,Actions 会自动生成随机 32 字节 AES 密钥
  • 普通推送和普通手动部署只保留现有 Secrets,不重新生成、不覆盖、不轮换
  • 部署后新消息与新附件自动使用 active key 加密
  • 管理员填写的 Telegram Bot Token 与 Webhook Secret 也使用同一密钥环加密后保存到 D1
  • 历史 D1 消息与 R2 附件不会被批量迁移,读取时兼容明文与密文

如果要手动指定首次部署密钥,提前添加同名 GitHub Repository Secret 即可。

如果要自动增量轮换已有密钥:

  1. 手动运行 Deploy Worker
  2. 勾选 rotate_encryption_key
  3. 工作流新增一个版本化密钥 Secret,并切换 active key ID
  4. 所有旧版本 Secret 与旧 JSON 密钥环保持不变

apply_encryption_keyring 是备用的手动覆盖入口。使用它时,Repository Secret 必须包含完整 JSON 密钥环,所有仍被历史消息、附件或 Telegram Bot Token 密文引用的旧 key ID 都要保留,再添加新 key 并更新 activeKeyId。删除旧 key 会导致对应历史密文无法读取。两个轮换选项不能在同一次运行中同时启用。

Cloudflare 不允许回读 Worker Secret。自动轮换通过“只新增新版本、永不读取或覆盖旧版本”规避这一限制;需要自行掌握和备份全部密钥时,应在首次部署前手动提供 JSON 密钥环。

这是服务端静态加密,不是端到端加密。Worker 在会话权限校验通过后解密内容,部署方和 Worker 运行环境仍位于信任边界内。管理员后台不再提供消息正文搜索或完整会话查看功能。

D1 自动迁移

每次部署都会在发布 Worker 之前检查目标 D1 的真实表、列、索引和触发器,并使用 edgechat_schema_migrations 表记录已经应用的迁移及文件校验值。

  • 新建 D1 会先执行完整 worker/schema.sql,再登记当前迁移基线
  • 已有 D1 只执行尚未具备结构的 worker/migrations/*.sql
  • 曾部署旧版未读角标实现的数据库会先把 channel_reads 游标合并到现行 message_reads,再移除阻塞消息表重建的遗留外键
  • Telegram Bridge 迁移会独立创建配置、映射表,并为消息增加外部发送者、文件来源和去重字段
  • 已执行迁移不会重复运行,避免重复添加列或覆盖现有数据
  • 如果数据库只完成了某项迁移的一部分,工作流会停止部署并报告缺少的结构,避免新代码连接旧数据库后持续返回 500
  • 已执行的迁移文件禁止直接改写;需要调整数据库时应新增排序更晚的迁移文件,并同步迁移清单

因此,fork 仓库同步上游代码后,只要 Cloudflare Secrets 指向正确账号,Actions 会同时更新数据库结构和 Worker,不需要手工登录 D1 执行 SQL。

后台更新检查

安装与维护

管理员可从左侧导航最底部的独立「安装与维护」入口打开 /admin/maintenance,手动检查 D1 连通性、迁移记录及实际表/列/索引/触发器、KV Sessions、可选 R2、三个 Durable Object 和必要环境变量,并查看 EdgeChat 与数据库版本、导出无密钥值的 JSON 诊断报告。页面不会自动轮询,也不会执行迁移、清库、GC 或重置配置;demo 会明确标注模拟结果。

部署和后台共用 worker/src/maintenance/schema-contract.ts 的采集与判定规则。npm run schema:generate 使用 SQLite 执行 worker/schema.sql,自动采集结构并附带既有迁移清单及 SQL 校验值,生成 worker/src/generated/schema-manifest.json。生成文件不提交,测试、网页主构建及 Wrangler 自定义构建会自动生成并打包;未来仍只需更新完整 schema、添加增量 SQL 并登记既有迁移清单,不需要另写后台检查表。

自定义部署配置应保留模板中的 [build] command = "npm run schema:generate"。手动发布时,在应用迁移后、部署 Worker 前,使用与迁移脚本相同的 CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_IDEDGECHAT_D1_DATABASE_ID 运行:

bash
node .github/scripts/prepare-d1-migrations.mjs --verify

验证不通过时不要继续发布。缺少迁移或 ledger 记录时先查看部署日志并重跑正常部署;校验值不一致、结构漂移或未知迁移时先备份并核对版本,不要手动改 ledger 或重放历史 SQL。实际结构多出的旧对象不会自动删除。

检查仅验证对象和列的存在,不比较列类型、索引定义或业务数据完整性;KV/R2 只做有限只读访问,DO health 不设置 alarm,因此结果不代表写入、解密、Cron 调度或消息投递的端到端验收。若 D1/KV 已不可用而无法登录,仍需从 Cloudflare 与部署日志排查。环境变量仅检查存在性,不能证明密钥正确或历史密文可解密。

版本更新

生产构建会自动记录本次部署对应的 GitHub 仓库、分支和提交。管理员进入“网站设置”时,浏览器会直接调用 GitHub Compare API 比对远端分支;也可以点击“检查更新”重新检查。这个过程只发生在前端,不会创建定时任务,也不需要新增 Cloudflare Secret。

为了保证结果准确:

  • 源码仓库需要保持公开,浏览器才能匿名读取比较结果
  • Actions 部署会自动使用 GITHUB_REPOSITORYGITHUB_REF_NAMEGITHUB_SHA
  • 手动部署应在 Git 仓库内基于已经推送的干净提交构建
  • 未提交改动、未推送提交或 GitHub API 暂时限流时,后台会显示无法准确检查,不会误报为已有更新

独立 Demo 工作流

纯前端演示站使用 .github/workflows/deploy-demo.yml,只允许手动触发。它读取独立的 DEMO_CLOUDFLARE_ACCOUNT_IDDEMO_CLOUDFLARE_API_TOKEN,构建 frontend/demo-dist 并部署 edgechat-demo

这个工作流不执行生产资源确认、D1 初始化或迁移、管理员写入和加密 Secret 准备,也不会使用生产部署的 Cloudflare Secrets。完整说明见纯前端 Demo

Android CI 与发布

.github/workflows/android-ci.yml 继续验证暂时弃用的原生 Compose 客户端,在 android/** 或 API v1 契约变化时运行 Gradle Wrapper 校验、单元测试、Lint 和 Debug APK 构建。

.github/workflows/capacitor-android-ci.yml 构建当前主要发行的 Web UI Android 客户端:使用 Node.js 24、Java 21 和 Android SDK 36,先构建并同步前端资源,再运行应用模块的单元测试、Lint、Debug APK 与 instrumentation APK 构建,最后上传 edgechat-capacitor-debug artifact。该客户端包名为 com.aozorae.edgechat.web,仍可与原生版并行安装。

.github/workflows/android-release.ymlandroid-v* 标签或手动触发,构建并同步 Vue 前端,再生成签名 Capacitor APK、AAB 和 SHA256SUMS.txt,最后创建 GitHub Release。原生 Compose 客户端不再进入该发行工作流。

发布前需要在 Repository Secrets 配置:

  • ANDROID_KEYSTORE_BASE64
  • ANDROID_KEYSTORE_PASSWORD
  • ANDROID_KEY_ALIAS
  • ANDROID_KEY_PASSWORD

签名 keystore 必须离线备份,仓库只在工作流运行期间从 Secret 恢复临时文件。纯 Android 和 Android 文档改动不会触发生产 Worker 部署;后端、前端、测试、迁移或部署脚本变化仍运行完整 Cloudflare 流程。

推荐权限

CLOUDFLARE_API_TOKEN 至少需要:

  • Workers Scripts:Edit
  • Workers Routes/Cron Triggers:Edit
  • D1:Edit
  • Workers KV Storage:Edit
  • R2:Edit

即使账号尚未开通 R2,也应保留 R2:Edit。工作流需要这项权限可靠地区分“尚未开通 R2”和“Token 无权访问 R2”;后者会按配置错误停止部署。

建议

  • 第一次使用前先确认仓库 Secrets 已填完整
  • 如果已经有现成资源,优先检查资源 ID 和命名空间是否正确
  • 管理员账号建议直接通过 Secrets 管理,不要手工修改数据库