# 运行目录迁移说明 `SMAIL_ROOT` 始终指向服务根目录,不能指向 `config`、`data` 或编译输出目录。 ```text 服务根目录/ ├── config/ # 仅五个当前配置文件 │ ├── config.json │ ├── smtp.json │ ├── email.json │ ├── ssl.json │ └── plugins.json └── data/ # 必须与配置一起备份,不得上传 Git ├── *.db # SQLite 数据库及其附属文件 ├── *.key # 原加密密钥,不可重新生成或替换 ├── ssl/ # 证书、私钥、签发账号、受管版本 ├── dkim/ # 邮件签名密钥 ├── backups-v2/ # 分区配置历史备份 ├── transaction/ # 配置事务与故障恢复 ├── migration-backups/ # 旧配置迁移备份 ├── config-audit-v2.jsonl └── legacy-config/ # 待验收后人工清理的废弃配置 ``` ## 升级旧部署 1. 停止后端及自动重启服务,确认没有其他进程读写数据库;关闭前端开发服务器。 2. 将整个旧 `config` 目录备份到受保护位置,包括数据库的 WAL、SHM 和日志文件。不要使用历史配置备份替换当前配置。 3. 编译配置工具:在 `backend` 中运行 `go build -o ../out/backend/smail-config.exe ./cmd/smail-config`。Linux 去掉 `.exe`。 4. 只读检查:`smail-config --root 服务根目录 --runtime-data`。 5. 确认已停服后执行:`smail-config --root 服务根目录 --runtime-data --apply`。 6. 核对迁移清单及文件哈希,启动新版后端,然后启动前端。Windows 开发入口为 `deploy/start-dev.ps1`,后端仍是 5201,前端仍是 80/443。 7. 验证登录、证书、配置保存、备份及审计。通过后才能清理 `data/legacy-config` 中明确废弃的文件;数据库、密钥和证书不能删除。 工具不会覆盖目标文件。未知项目、符号链接或目标冲突会阻止迁移。操作失败时逆序回滚已移动项目;回滚失败时保留现场和原始备份,禁止启动旧后端或新建数据库。迁移独占锁为 `data/.runtime-migration.lock`;进程崩溃或回滚失败后会保留锁并阻止启动,管理员必须先确认没有运行进程、核对源和目标文件与备份一致,再移除残留锁并重新检查。已移动项目不会重复覆盖。嵌套 SQLite 目录须根据 `database.localRef` 人工核对,未知目录不会被自动处理。 若升级前只有旧格式 `config.json`,先执行运行目录迁移,再执行 `smail-config --root 服务根目录 --apply` 转换为五个分区配置。不要先生成新密钥,也不要用旧格式配置覆盖现有分区配置。迁移工具不自动备份整个数据库目录,也不自动停止服务;停服和完整备份是执行前提。 迁移只移动运行文件,不改写五个配置的字节、代次和摘要。旧 `config/ssl` 相对引用先通过原摘要校验,再在运行态解析到 `data/ssl`;下一次正常保存会写入新引用。历史备份不改写摘要,恢复时沿用同一兼容规则。 ## 权限与回退 - Linux:`config`、`data` 由专用服务账号拥有,目录 0700、敏感文件 0600;不要给普通账号开放读取权限。 - Windows:正式服务由安装脚本设置服务账户和受保护 ACL;开发模式仍明确停用管理员恢复通道,不提升普通邮件业务权限。 - 加密密钥必须与数据库及配置一同迁移,不能只复制 JSON。已初始化部署缺少数据库或关键密钥时,新后端拒绝启动,不会默默生成空库。 - 需要回退时先停服,使用迁移前的完整备份与对应旧二进制成套恢复;若迁移后已经收信或修改账号,先备份最新数据并制定数据回迁方案,不能直接覆盖。 - 前端开发证书默认读取 `data/ssl/xuans.com.crt` 与 `data/ssl/xuans.com.key`;自定义环境变量指向旧位置时需要同步修改。