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 | 可选的完整服务端加密密钥环;不配置时首次部署自动生成。 |
触发方式
- 推送到
master或main - 在 GitHub Actions 页面手动触发
workflow_dispatch
工作流步骤
- 拉取代码
- 安装依赖
- 构建前端
- 检查或创建 Cloudflare 资源
- 生成 CI 专用
wrangler.ci.toml - 首次创建 D1 时初始化数据库
- 检查并执行尚未应用的 D1 迁移
- 使用随代码自动生成的 schema manifest 验证迁移记录和完整结构
- 可选写入管理员账号
- 检查并准备 Worker 加密 Secret
- 部署 Worker
R2 附件能力
资源检查步骤会调用 Cloudflare 官方接口 GET /accounts/{ACCOUNT_ID}/r2/buckets?per_page=1 判断目标账号是否已经开通 R2。
- 已开通 R2:继续复用或创建
cfchat-filesbucket,并按原方式建立FILESbinding - Cloudflare 返回错误码
10042:继续部署 Worker,但从 CI 配置中移除FILESbinding - Token 权限不足、账号 ID 错误或其他 Cloudflare API 异常:停止部署,避免把配置错误误判为未开通 R2
没有开通 R2 时,登录、文字聊天和后台管理仍可使用;用户上传附件时会直接看到“当前部署没有绑定 R2,无法上传附件”。附件读取和 Telegram 文件同步同样不可用。开通 R2 后重新运行 Deploy Worker,工作流会幂等创建或复用 bucket,并自动恢复附件能力。
服务端加密密钥
默认自动模式使用独立的版本化 Worker Secrets 保存每一把密钥,并用单独的 active key ID 指向新写入数据应使用的版本。已有的 EDGECHAT_ENCRYPTION_KEYRING 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 即可。
如果要自动增量轮换已有密钥:
- 手动运行
Deploy Worker - 勾选
rotate_encryption_key - 工作流新增一个版本化密钥 Secret,并切换 active key ID
- 所有旧版本 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_TOKEN、CLOUDFLARE_ACCOUNT_ID、EDGECHAT_D1_DATABASE_ID 运行:
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_REPOSITORY、GITHUB_REF_NAME和GITHUB_SHA - 手动部署应在 Git 仓库内基于已经推送的干净提交构建
- 未提交改动、未推送提交或 GitHub API 暂时限流时,后台会显示无法准确检查,不会误报为已有更新
独立 Demo 工作流
纯前端演示站使用 .github/workflows/deploy-demo.yml,只允许手动触发。它读取独立的 DEMO_CLOUDFLARE_ACCOUNT_ID 和 DEMO_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.yml 由 android-v* 标签或手动触发,构建并同步 Vue 前端,再生成签名 Capacitor APK、AAB 和 SHA256SUMS.txt,最后创建 GitHub Release。原生 Compose 客户端不再进入该发行工作流。
发布前需要在 Repository Secrets 配置:
ANDROID_KEYSTORE_BASE64ANDROID_KEYSTORE_PASSWORDANDROID_KEY_ALIASANDROID_KEY_PASSWORD
签名 keystore 必须离线备份,仓库只在工作流运行期间从 Secret 恢复临时文件。纯 Android 和 Android 文档改动不会触发生产 Worker 部署;后端、前端、测试、迁移或部署脚本变化仍运行完整 Cloudflare 流程。
推荐权限
CLOUDFLARE_API_TOKEN 至少需要:
Workers Scripts:EditWorkers Routes/Cron Triggers:EditD1:EditWorkers KV Storage:EditR2:Edit
即使账号尚未开通 R2,也应保留 R2:Edit。工作流需要这项权限可靠地区分“尚未开通 R2”和“Token 无权访问 R2”;后者会按配置错误停止部署。
建议
- 第一次使用前先确认仓库 Secrets 已填完整
- 如果已经有现成资源,优先检查资源 ID 和命名空间是否正确
- 管理员账号建议直接通过 Secrets 管理,不要手工修改数据库
