Hanori花织 · 使用文档
自托管

备份与升级

在迁移、升级和回滚前保护数据库、文件与加密数据。

Hanori 的数据库中可能包含 Bot 配置、认证、消息、档案、记忆、日志、RSS、总结、生成记录和集成凭据。生产升级的第一步应是可恢复的备份,而不是直接重建容器。

数据库导出以流式方式写入压缩归档;导出或写盘失败时会终止本次导出进程并尝试删除部分文件。若日志提示部分文件清理失败,需检查备份目录的权限和磁盘状态。远端上传失败时,有效的本地备份仍会保留,备份记录会注明远端上传错误。备份完成后,保留策略读取或清理查询失败会记录告警,不会改变该次备份的完成状态;可检查日志并在后续备份时重试清理。单条旧备份的本地文件或记录清理失败也会在日志中注明备份 ID;其他符合保留策略的旧备份继续清理,失败项可在修复文件权限等问题后重试。

删除本地备份遇到权限或文件系统错误时,记录会保留,后续远端删除不会执行。修复目录或文件问题后可重试;本地文件已不存在时仍可继续清理记录。

取消备份下载会停止服务器端的文件读取,取消后可重新下载同一备份。

文件名前缀支持中文和空格,但不能包含斜杠、反斜杠或控制字符,也不能用于指定目录。空前缀使用默认值。已有不安全前缀需先修改后再创建备份;异常历史文件名的下载和删除会被拒绝,请由维护者核对记录与实际文件后处理。

WebDAV 会把文件名作为一个路径组成部分编码,保留配置地址中的目录和查询参数。旧版本若使用含 #、? 或百分号的前缀,请核对远端实际对象名称;升级不会自动移动或删除旧错误路径上的对象。

备份什么

至少保护以下三类数据:

  1. PostgreSQL 数据库和迁移状态。
  2. 图片、收到的文件、备份和编码工作区等挂载目录。
  3. .env 或部署平台 Secret 的安全副本,尤其是 ENCRYPTION_KEY、认证 secret 和外部集成凭据。

密钥备份与数据库必须分开保护。只有数据库没有加密 key,恢复后的敏感配置可能无法解密;只有 key 没有数据库,也不能恢复业务数据。

Bot 数据导出中的插件配置

Bot 数据导出的 JSON 保留插件的普通配置,移除 Cookie、Token、ASR API Key 等敏感字段及其密文,并排除临时转录任务和结果。导入后插件保持停用,需要重新提供凭据并手动启用;原 Bot 的密文不能复制给新 Bot 使用。JSON 导出不替代包含数据库、文件和加密密钥的完整备份。

完整 PostgreSQL 备份仍可能包含加密插件配置和未过期转录正文,应按敏感数据保护;不要把它与已脱敏的 Bot JSON 导出混为一谈。音频转换使用的 mediajobs、mediacontrol 临时 volume 无需备份,也不应把临时音频加入长期文件归档。插件的固定版本制品保存在 app 数据目录下,需随持久挂载目录一并保护。

转录正文从任务创建起保留 24 小时,备份不是延长可用期或重新授权导出的方式。恢复数据库后,下载、转换阶段的中断任务可有限恢复,已进入转录阶段的任务不会自动再提交给供应商;先核对旧请求和账单,再决定是否创建新任务。

升级前清单

  • 记录当前版本、commit 或镜像 digest,以及上一次 ready 检查结果。
  • 在维护窗口创建数据库备份,并用恢复工具或临时数据库验证可读。
  • 确认目标版本的迁移文件已经存在,且不会改写已部署迁移。
  • 记录 COMPOSE_PROFILES,不要意外启用或关闭 coding 或 media worker;分别保留各自独立的 worker secret。
  • 通知正在使用 Bot 的成员,避免把迁移期间的短暂不可用当作业务失败。

将历史加密密钥迁入显式配置

当前版本要求所有环境提供非空 ENCRYPTION_KEY。已有实例升级前,先核对正在运行的旧版本完整 commit,以及真正生效的环境配置。部署平台 Secret、Compose 和进程环境变量可能覆盖 .env;下面的离线工具只读取指定文件,不能判断线上实际使用了哪个值。

如果旧实例未显式配置密钥,可在保留旧 Git 历史的私有源码仓库中,用新版本脚本生成一个新的配置文件:

node scripts/preserve-upgrade-env.mjs \
  --legacy-ref <已核实的旧部署完整commit> \
  --input /受保护目录/当前.env \
  --output /受保护目录/升级.env

请替换上面的占位符,使用实际的完整 40 位 commit。该 commit 必须对应旧实例,并且本地 Git 能读取它。不要把私有 Git 历史推送到公开仓库;独立公开仓库或源码归档通常不包含恢复所需的旧 commit。

工具优先保留输入文件中已有的非空密钥;只有缺失或为空时,才从指定 commit 的旧源码中读取历史默认值。它不联网、不访问数据库、不改写输入文件,也不自动启用输出文件。新文件以 0600 权限独占创建,已有文件、符号链接和重复关键配置会被拒绝。密钥以单引号保存,避免 Compose 展开 $ 或解释 #;无法无损表示的配置(例如含单引号的密钥)会安全拒绝,此时应通过受保护的部署 Secret 保留实际原值,不能换成新随机值来绕过错误。

在本地安全核对新文件,完成数据库与原配置备份后,由实例维护者将它接入部署。不要将文件内容贴进 issue、日志或 PR。此步骤保留原密钥,使原密文继续可读;它不是密钥轮换。如果历史密钥已暴露,需另外安排经过验证的密文重加密流程。

若同一次升级还需恢复以前写在源码里的图片 MCP 地址,可在上述命令末尾添加 --restore-image-mcp。工具从同一旧 commit 读取地址,保留已有非空 PIXAI_MCP_URL,不会把旧服务地址写入公开代码。该选项不会迁移 OAuth token;部署后仍需由 owner 重新授权。不加此选项时,不会自动恢复图片集成。

执行升级

使用实例维护者提供的更新脚本或 Compose 流程,先拉取目标版本,再构建并启动数据库和 app。应用启动时会执行尚未应用的 Drizzle 迁移;迁移完成后再启动 BotPool 和可选 worker。

对于通过 Git 克隆且数据库已经运行的直接 Compose 部署,可以指定一个已审查的 release tag:

./scripts/update-production.sh --version vX.Y.Z

用远程仓库真实存在的版本替换 vX.Y.Z。脚本从 DEPLOY_REMOTE(默认 origin)读取 tag 对应的完整 commit,验证数据库备份后进入 detached HEAD,构建并等待 /api/health/ready。只允许当前代码的向前升级,不自动降级或切换到没有共同历史的仓库。--force 可与 --version 一起使用以重新部署当前版本。不要把成功备份等同于已完成数据库恢复演练。

已有维护者部署仍可在 main 分支执行不带 --version 的旧命令。跟随 main 使用的是开发分支状态;第三方长期实例应选定已发布 tag。备份目录可以用 DEPLOY_BACKUP_DIR 指定,旧的 COS_BOT_BACKUP_DIR 继续兼容;Compose 项目名通过进程环境变量 DEPLOY_PROJECT_NAME 指定,默认仍是 cos-bot-prod。这些参数不会自动读取 .env,请在调用命令时显式传入或写入自己受保护的运维配置。

更换产品名或源码仓库

从图片 MCP 地址固定在源码中的版本升级时,先等待已有生图任务完成,在受保护的环境配置中显式设置 PIXAI_MCP_URL,重建 app 后由 owner 重新授权。旧授权没有服务地址绑定,升级后不会自动复用;未设置地址时只关闭图片 MCP 集成。不要把旧服务的数据库凭据、PixAI key 或 OAuth token 复制到公开源码。

界面名称或仓库目录的变化不需要数据库迁移。继续使用原来的 Compose 项目名、数据库名、volume、认证组织标识和 .env 中的稳定密钥。改变 Compose 项目名可能创建新的空 volume,使原数据看起来消失。

Hanori · 花织沿用早期 cos-tool-bot 实例的存储标识:@cos-tool-bot/* workspace scope、cos_tool_bot 数据库、默认 cos-bot-prod Compose 项目、认证组织 slug、浏览器语言与 Mini App 本地存储 key,以及备份文件默认前缀继续兼容。旧组织默认名在工作台中显示为新品牌,数据库记录和自定义组织名称不会被改写。已有 OAuth 客户端无需为了显示名称重新注册;新建客户端会使用 Hanori 名称。

私有源码仓库与独立初始化的公开源码仓库可能没有共同 Git 历史。不要用 git pull、强制 reset 或改远程后的一键升级来跨越这条边界;在新目录取得目标源码,带上受保护的配置,先备份数据库和文件,再以原来的 Compose 项目名重建。停止旧 app 后才启动新 app,避免同一 Telegram Bot 被两个实例同时轮询。Dokploy 的新应用会有新的资源命名,需要按平台的备份恢复流程迁移全部 volume,不能只移动源码。

源码归档没有 .git。构建归档前,设置公开 release 对应的完整 Git SHA 为 APP_VERSION;健康接口版本继续代表实际部署来源,不使用产品 SemVer 替代。归档部署使用手动 Compose 更新流程,不运行需要 Git 的更新脚本。

如果从不带 pgvector 的 PostgreSQL 镜像升级,先确认数据库大版本和 volume 兼容,再让应用创建 vector 扩展、列和索引。embedding 回填可以后置;未回填的数据通常仍可走关键词搜索,但语义搜索覆盖不完整。

升级后验证

按这个顺序检查:

  1. docker compose ps 中 app、db 以及启用的 worker 状态正常。
  2. /api/health 和 /api/health/ready 返回成功及预期版本。
  3. 面板能登录,Bot 列表和设置可读写。
  4. Telegram /help、一次普通 AI 回复和 /status 工作正常。
  5. 最近一次迁移已应用,备份页面仍能看到历史记录。
  6. 只有在确认稳定后,才测试图片、RSS、MCP、GitHub 或 Lark 等可选集成。

失败和回滚

构建失败、迁移失败或 ready 超时都应先保留日志和当前数据库,不要反复执行不可逆命令。根据维护者的回滚策略恢复上一镜像或 commit;如果迁移改变了 schema,必须使用对应的向前修复或经过验证的数据库备份,不要手工删除迁移记录。

回滚后重新检查认证会话、Bot Token 解密、Telegram 投递和外部集成。生产状态应以健康接口、面板和真实 Bot 流程共同证明;CI 或本地构建通过只能证明对应检查范围内没有发现问题。

隔离恢复演练

可在测试机运行 node scripts/smoke-deployment.mjs,使用合成账号和停用 Bot,在独立 app、数据库与 volume 中检查恢复后的登录、加密凭据读取和文件完整性。脚本不会读取或恢复生产备份;它验证部署路径,不能代替定期检查你自己的备份。

提供 --previous-sha <上一支持版本的完整 Git SHA> 可一起验证跨版本升级。升级前备份,恢复保留原 ENCRYPTION_KEY;错密钥即使健康检查通过,凭据也可能无法解密。迁移失败时保留原备份并检查 schema 兼容性,不通过自动降级修复。详见隔离部署检查。

本页内容