7.3 KiB
部署后自动归档与证书保留
已确认要求
- 正式程序在任意部署目录启动后自动创建目录,不依赖手动整理或开发脚本。
- 已采用
config/ssl/data/log布局的旧部署,启动时自动归档三把业务密钥,保留原字节。 ssl/managed自动保留两套受管证书材料,后续导入、续期、应用及重启继续执行。- 域名证书原文件继续保存在
ssl/根目录,不与业务加密密钥混放。 - 模拟部署使用
yunx-test/,修改完成后必须完整构建并核验最新二进制。
程序创建的目录
部署目录/
├── config/ # 初始化完成后的五个生效 JSON
├── ssl/
│ ├── credentials/
│ │ └── credential.key
│ ├── external-email-encryption/
│ │ └── external-email-encryption.key
│ ├── external-email-fingerprint/
│ │ └── external-email-fingerprint.key
│ ├── dkim/
│ ├── managed/ # default 与 upload 合计保留两套
│ ├── 域名.crt
│ └── 域名.key
├── data/
├── log/
├── smail
└── smail-admin
目录由主服务启动入口 InitializeDeployment 创建;密钥由对应业务首次需要时创建,不能为凑齐文件生成无用密钥。Windows 二进制带 .exe 后缀。初始化未完成时不会伪造五个完成态配置文件。
三个目录分别保存配置凭据加密密钥、外部邮箱加密密钥、外部邮箱检索指纹密钥。ACME 账户密钥的进一步归档不在本次三个业务目录改动中,原文件继续保留。
启动迁移
启动先检查再移动:已初始化部署缺少密钥或数据库、新旧密钥重复、密钥不是 32 字节、存在链接或无效目标目录时拒绝继续,不覆盖、不重新生成替代密钥。Linux 还检查密钥文件权限。
有效的 ssl/credential.key 等旧文件使用重命名归档到业务目录,内容不变,因此旧配置密文、外部邮箱密文及指纹仍有效。每次移动后同步目录;迁移中断后允许下次启动继续,重复启动不会再次生成密钥。
更早的 config/ 或 data/ 混放部署仍须执行原有完整迁移流程,不能只搬三把密钥而遗漏数据库、证书和历史引用。
两份保留规则
- 一份是完整的证书和私钥组合,不是两个单独文件。
- 当前生效证书优先保留;提交新版本时保留上一份材料;其余按版本目录时间排序补足两份。
- 待应用候选、正在导入或续期的材料、磁盘已提交引用受到保护;操作进行时可能暂时超过两份,应用或取消后再次清理。
- 启动后、定期证书维护、配置应用、回滚、取消候选及重新加载时自动执行。
- 仅删除程序识别的历史版本。未知文件、链接、无法安全检查的目录保留并告警;事务恢复未完成时暂停清理。
- 私钥文件锁保护跨进程暂存,配置状态锁协调提交与清理。停止或替换管理器时释放暂存锁。
- 上一份证书过期不会阻止正常清理,但运行加载和回滚仍执行完整证书有效期、强度、配对检查。
- 已清理证书的历史配置不能回滚,预览和执行均返回明确中文错误,必须重新导入有效证书。
域名文件与运行引用的边界
ssl/域名.crt、ssl/域名.key 是用户放置的证书原文件,自动归档和清理不删除它们。
本次没有将服务运行引用改成根目录文件。 自定义证书仍经校验后导入 ssl/managed/.../version-...,配置事务切换成对的受管引用,避免外部文件变化或两文件替换期间配对不一致。若要求运行引用也固定为 ssl/域名.crt 与 ssl/域名.key,还需实现完整的成对发布、失败恢复和备份引用迁移,不能只复制文件或直接改 JSON 冒充完成。
验证与边界
- 自动化回归覆盖新建目录、旧密钥字节不变、中断续迁、重复启动、冲突拒绝、跨模式总数两份、暂存保护、未知文件保护、过期前版本、旧
current清理及历史回滚拒绝。 test/deployment/verify_ssl_startup.py在原前后端停服且最新包已部署后运行,将原yunx-test暂存至test-log,用同一二进制在空yunx-test正式启动两次,再恢复原部署。所有测试产物保留,不删除业务库。- 空目录正式启动只验收自动目录创建和初始化页面可达,不等于完成整个首次初始化、管理员恢复权限或插件生产隔离验收。
- Linux 编译通过不等于 Linux 生产运行验收。正式管理员恢复通道的保护不降低。
本轮实测记录(2026-09-08)
以下记录来自本轮最新源码构建,不以手工创建当前目录代替启动验证。
| 验证项目 | 实测结果 | 本地记录 |
|---|---|---|
| 空目录正式启动两次 | 仅放两个程序,使用 smail.exe -p 15201,两次均自动创建部署目录及五个 SSL 子目录,初始化页面返回 200 |
test-log/ssl-startup-20260908-202756/result.json |
| 旧部署自动升级 | 三把业务密钥归档前后字节不变,旧位置不再保留重复文件 | test-log/ssl-upgrade-result-20260908.json |
| 旧证书自动清理 | 由新程序启动完成,受管材料从 11 套收敛为 2 套,当前证书和私钥仍存在 | 同上 |
| 原文件保护 | 五个生效 JSON、根目录证书、ACME 密钥及其他原 SSL 文件字节不变;已有运行目录完整恢复 | 同上及空目录启动记录 |
| 邮件 TLS | 465、993、995 均完成 TLS 1.3 握手,实际证书指纹与当前配置指向的证书一致 | test-log/ssl-upgrade-tls-20260908.log |
| 全量自动化回归 | 前端 140/140、部署 4/4、Go 全量通过 | test-log/run-2026-09-08T12-25-13-445Z-12312/ |
| 专项并发检查 | 配置、运行路径、配置凭据、外部邮箱及 SSL 设置包的 -race 测试通过 |
test-log/run-2026-09-08T12-26-15-343Z-27176/ |
| 最新部署包 | 前端、三个插件、Windows 内嵌资源主程序及管理员程序完成构建,源码指纹和部署哈希通过 node deploy/build-state.mjs verify --deployed 核验 |
out/build-state.json |
当前页面优化环境保留为前端源码热更新、后端最新编译程序,运行配置统一读取 yunx-test/config/。前端 HTTPS 及后端 /api/ping 均返回 200;后端使用已明确标记的开发恢复通道豁免参数,与上表不含该参数的空目录正式启动测试分开记录。
本轮没有进行浏览器页面交互验收,也没有宣称完整生产初始化或 Linux 运行验收通过。前端已有富文本编辑器分包体积提醒不在本次修改范围内。
任务状态
- [✓] 正式主程序自动创建业务目录,不依赖部署脚本创建。
- [✓] 已采用 SSL 布局的旧部署自动迁移三把业务密钥,重复启动不更换密钥。
- [✓] 受管证书正常稳定状态保留两套,保护生效、暂存和恢复所需材料。
- [✓] 最新包部署、空目录启动、旧部署升级及邮件 TLS 验证完成。
- [!] 根目录域名文件直接作为运行引用尚未改造;本轮只保证原文件保留,并继续使用已校验的受管副本。
- [!] Linux 正式运行、完整首次初始化及正式管理员恢复流程尚未完成本轮实机验收。