Scert/doc/生产部署与运维说明.md

395 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scert 生产部署与运维说明
> 2026-09-27 验收入口:部署当前候选前,先按《整改任务规格与验收约定》及《Scert整改任务执行清单》核对版本、环境、授权与 12 层生产门禁。下文历史拓扑不是当前服务器状态,不因旧批次通过而跳过本次实机检查。源码、候选包与证据边界见《仓库目录与产物边界说明》。
> 2026-09-27 正式范围:仅交付 Web 和 Windows/Linux 服务端。Wails 历史源码不参与发布,桌面窗口、托盘、更新、桌面配置及 UI 测试不作为生产门禁。CLI 仅作为服务端运维工具;本文件的 Linux 部署步骤不代表 Windows Service 已验收。
> 2026-09-15 云主机验收拓扑已更新:`47.108.78.12` 为管理机,`8.137.23.95` 仅为推送测试机。下文局域网地址是历史测试示例,不能用于本轮部署。最新包、实机证据、禁止修改范围及生产阻塞见 [发布加固与实机验收记录](发布加固与实机验收记录.md)。
## 1. 文档范围
本文档用于 Scert `0.1.0` 的 Linux 生产部署、升级、备份、恢复、监控和故障处理。当前测试拓扑为:
| 主机 | 用途 | 允许部署内容 |
| --- | --- | --- |
| `192.168.2.3` | Scert 服务主机 | Scert、systemd unit、Nginx 反向代理 |
| `192.168.2.4` | SSH 和证书推送目标 | SSH、公钥、证书目标目录、Nginx;禁止部署 Scert |
开发验收端口:
- Scert:`127.0.0.1:9004`
- Nginx:`0.0.0.0:9003`
正式生产通常由 Nginx 监听 `443`。`9003` 只用于当前隔离网络开发测试,`9004` 必须保持回环监听,不得对公网开放。
## 2. 生产准入条件
部署前必须全部满足:
- [ ] 使用 Go `1.26.6` 或更高兼容安全版本完成发布构建。
- [ ] `go test -count=1 ./...`、`go test -race -count=1 ./...`、`go vet ./...`、`go mod verify` 和 `govulncheck ./...` 通过。
- [ ] Web 前端生产构建通过,生产依赖不存在高危或严重漏洞。
- [ ] Linux amd64 发布包中的 `scert`、`scert-admin`、`web/`、systemd unit 和安装器来自同一提交。
- [ ] 目标主机时间同步正常,系统 CA、OpenSSH、Nginx 和安全更新处于受支持状态。
- [ ] Scert 仅绑定 `127.0.0.1`,Nginx 到 Scert 的 HTTPS 上游证书校验已开启。
- [ ] 已完成一次停服完整备份、篡改拒绝、恢复和失败回滚演练。
- [ ] 已确认 SSH 主机指纹并验证证书推送、私钥权限、Nginx 重载和失败回滚。
- [ ] 管理员账号使用独立强密码,DNS、SMTP、HTTP 通知和 SSH 私钥没有写入代码、日志、文档或 Git。
任何一项未满足时,只能作为开发或受控试运行环境,不能宣称正式生产准入。
## 3. 发布构建
### 3.1 后端验证
```bash
cd backend
go test -count=1 ./...
go test -race -count=1 ./...
go vet ./...
go mod verify
govulncheck ./...
```
### 3.2 Web 构建
```bash
cd frontend
npm ci
npm run build
npm audit --omit=dev --audit-level=high
```
### 3.3 Linux amd64 二进制
```bash
cd backend
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -trimpath -ldflags "-s -w" -o ../release/linux-amd64/scert ./cmd/scert
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -trimpath -ldflags "-s -w" -o ../release/linux-amd64/scert-admin ./cmd/scert-admin
```
发布目录必须包含:
```text
linux-amd64/
├── install-linux.sh
├── scert
├── scert-admin
├── web/
└── systemd/
```
发布包应额外生成 SHA-256 清单并通过可信通道核对。安装器会再次验证二进制是 Linux amd64 ELF,并拒绝符号链接或特殊 Web 文件。
## 4. Linux 安装与升级
### 4.1 首次安装
```bash
chmod +x install-linux.sh scert scert-admin
sudo ./install-linux.sh --source-dir . --certificate-dir /ssl
```
安装器不会自动启动服务,也不会创建公网防火墙或云安全组规则。首次安装还没有正式配置时,应先启动服务,再通过独立 Bootstrap HTTPS 页面初始化;不需要 Linux 图形界面。
默认初始化监听 `0.0.0.0:8080`。管理员应预先在主机防火墙和云安全组中只对受信任的管理来源放行该端口。如果已有端口占用,先设置 `SCERT_SERVER_PORT` 使用空闲端口。云主机公网 IP 不在本机网卡上时,先使用 `sudo systemctl edit Scert` 写入以下配置(示例 IP 必须替换为实际管理机 IP):
```ini
[Service]
Environment="SCERT_BOOTSTRAP_PUBLIC_IP=203.0.113.20"
```
`SCERT_BOOTSTRAP_PUBLIC_IP` 只决定临时初始化地址和证书的 IP,不会改变监听地址、云安全组或最终管理地址。命令行运行时对应参数是 `scert serve --bootstrap-public-ip <服务器公网IP>`。修改 systemd 配置后执行:
```bash
sudo systemctl daemon-reload
sudo systemctl enable Scert
sudo systemctl start Scert
sudo systemctl status Scert --no-pager -l
sudo cat /run/scert/bootstrap-url
```
通过可信运维通道读取并在浏览器打开完整 HTTPS 地址,不能只复制 IP 部分。链接片段包含短期一次性令牌;不要复制到日志、截图、工单或普通文档。地址文件仅允许服务用户和管理员读取,完成初始化或服务退出后会清理;令牌或会话过期时重启尚未初始化的服务再读取新地址,不要删除正式配置强制重新初始化。
临时 HTTPS 使用自签名证书,不代表公共 CA 信任。浏览器首次打开裸 IP 地址时,应先查看证书详情,通过已核对 SSH 主机身份的运维连接或云控制台读取当前启动日志:
```bash
sudo journalctl -u Scert -b -n 30 --no-pager
```
找到最新的 `Bootstrap 临时证书 SHA-256 指纹`,与浏览器证书详情的 SHA-256 指纹逐字比较(忽略显示分隔符和大小写)。必须一致才打开含一次性令牌的完整链接并填写敏感配置;不一致立即停止,不要输入 RAM 凭据或管理员密码。每次未初始化服务重启都会生成新证书,旧日志的指纹不能用于当前核对。指纹是公开证书摘要,日志不包含完整初始化链接、令牌或私钥。不得把“忽略证书警告”本身当作生产 TLS 验收;本轮仍缺少真实浏览器核对证据。
向导依次配置管理员、存储、阿里云 RAM 与域名验证、通知和正式管理入口:
- SQLite 使用本机文件;MySQL/PostgreSQL 使用预先创建的专属数据库及最小权限账号,不能用生产共享库做初始化测试。
- MySQL 必须启用 TLS 并校验服务端证书及主机名,当前使用系统信任库;PostgreSQL 使用 `sslmode=verify-full`,可指定服务端可读的根证书绝对路径。
- 数据库和 DNS 验证成功后保存的是短期验证状态;修改输入或状态过期需重新验证,不允许手填内部凭据引用。
- 正式入口可选择域名或 IP;域名证书需要真实 DNS/ACME 验证,IP 入口当前为自签名证书。默认 ACME staging 证书也不受公共信任,不能当作 production 证书。
- 保存成功后,临时初始化服务撤销会话并关闭,再自动加载正式配置启动服务,页面转到返回的正式 HTTPS 地址,无需手工重启切换。
若首次端口与正式端口不同,应由管理员预先准备正式端口规则,确认切换后关闭不再需要的初始化端口。服务不会代替管理员修改云安全组。固定及动态生成的 Linux systemd unit 显式设置 `SCERT_BOOTSTRAP_FIREWALL_MODE=external`:不运行 UFW/firewalld 查询和写入命令,完成响应及运维日志明确提示端口尚未检查。管理员应在首次访问前按受信任来源放行所需端口;反向代理模式仅允许代理访问内部端口,不能为方便初始化而向公网开放内部端口。
直接执行 `scert serve` 默认仍为 `auto`,自动防火墙操作限时三十秒,权限错误必须中止初始化,不会因失败自动切换外部模式。使用外部策略时可显式传入 `--bootstrap-firewall-mode external`,参数优先于同名用途的 `SCERT_BOOTSTRAP_FIREWALL_MODE` 环境变量。策略只能由本机启动配置选择,不能由浏览器提交。2026-09-17 已通过非特权 systemd 的隔离 Bootstrap 启动与重启协议检查,正式初始化完成及公网可达性仍待验收,不得将整个 Scert 服务改成 root 或取消加固。
主服务地址族白名单必须包含 `AF_NETLINK`,用于 Go 读取本机网卡并生成临时证书;缺失时会出现 `netlinkrib: address family not supported by protocol`。保留空 capability 集,不需要授予 `CAP_NET_ADMIN`。此要求只适用于主服务,不得照搬到仅允许本地 IPC 的超级管理员恢复服务。
反向代理方案应在初始化完成后再应用第 5 节的回环监听配置;若预先设置 `SCERT_SERVER_HOST=127.0.0.1`,远程浏览器将无法直接访问 IP 初始化端口。`SCERT_SERVER_PORT` 等环境变量会持续覆盖向导保存的配置,应与最终选项一致。
上述是新版源码的预期安装流程,不代表本轮已构建发布包或完成 Linux systemd 实机验收。
### 4.2 升级
安装器禁止在 `Scert.service` 或 `Scert-admin.service` 运行时覆盖程序。升级顺序:
停服核验使用 `systemctl show` 同时读取加载状态、活动状态、子状态、主进程、控制进程和排队任务。仅允许已加载的 `inactive/dead`、无进程的 `failed/failed`,以及首次安装的 `not-found/inactive/dead`;主进程与控制进程必须都为零,任务必须为空。查询失败、字段缺失、启动中、停止中、重载中或 masked 状态均在写入前拒绝。失败状态获准替换文件不代表原故障已解决,启动前仍需检查退出原因。
这是安装前的状态检查,不是与 systemd 的原子互斥。维护窗口内不得有其他管理员、定时任务或自动化工具并发启动服务;安装器不能防止检查完成后外部又启动服务。
```bash
sudo systemctl stop Scert-admin
sudo systemctl stop Scert
sudo -u Scert /scert/scert --config /scert/conf/scert.json backup
sudo ./install-linux.sh --source-dir /tmp/scert-linux-amd64
sudo systemctl start Scert
sudo systemctl status Scert --no-pager -l
```
没有显式传入 `--certificate-dir` 时,升级会读取 `/scert/conf/installation.json` 并保留既有证书根目录。升级不得覆盖 `/scert/conf/scert.json`、数据库、主密钥、敏感配置、证书和备份。
安装器在任何发布文件写入前检查既有目标类型;文件目标不能是目录,Web 目录不能包含符号链接或特殊文件。升级前发布文件会保留在 root 所有、权限 `0700` 的 `/scert/.install-XXXXXXXX` 中,`targets.txt` 按行记录目标,`before-0` 等编号与行号减一对应。不要删除该目录,确认新版本业务验收完成后再按保留策略人工处理。
Web 使用整目录替换,旧资源不会继续留在当前 Web 目录中;原目录和升级副本均保留。安装器捕获非零退出、INT 和 TERM 时会尝试恢复安装记录、两个程序、Web、两个 unit、证书目录 drop-in 和两份服务说明,并重新加载 systemd。失败现场保存在同一目录的 `failed-*` 中,不启动或启用服务。若提示“安装回退不完整,禁止启动服务”,必须先核查保留目录与 systemd 状态,不能继续执行启动命令。
此回退仅涵盖安装中的发布文件变更,不回退服务用户创建、既有业务目录权限规范化,不替代停服数据库备份;断电、SIGKILL、磁盘故障及安装成功后启动新程序造成的数据迁移,也不保证自动恢复。需要回到旧版本时,应保留现场,使用已校验的旧版完整发布包重新安装;若新程序已经改写数据库,应先按对应版本的备份恢复流程处理,不得仅覆盖可执行文件。
仓库提供 `deploy/tests/install-linux-test.py`,仅用于 Linux root 下的隔离文件安装测试。它以私有挂载命名空间映射固定安装路径,使用新建测试目录和 systemctl 故障注入桩,保留全部产物;要求指定既有普通证书挂载点及挂载点之外的产物目录。该测试不能代替真实 systemd 升级、启动、就绪检查和完整业务回退验收。
### 4.3 systemd 安全边界
主服务使用独立 `Scert` 用户、`UMask=0077`、`NoNewPrivileges`、私有设备和临时目录、内核与控制组保护、只读系统目录和受限地址族。安装后必须验证:
```bash
sudo systemd-analyze verify /etc/systemd/system/Scert.service
sudo systemd-analyze security Scert.service
sudo systemctl show Scert -p User -p Group -p NoNewPrivileges -p ProtectSystem
```
不得为方便调试改成 `root` 运行,也不得扩大 `ReadWritePaths` 到整个文件系统。
## 5. 网络与反向代理
### 5.1 Scert 监听
生产配置或 systemd 环境覆盖:
```text
SCERT_SERVER_HOST=127.0.0.1
SCERT_SERVER_PORT=9004
SCERT_SERVER_HTTPS_MODE=proxy
SCERT_WEB_ENABLED=true
```
验证:
```bash
sudo ss -lntp | grep 9004
curl -k --fail --silent --show-error https://127.0.0.1:9004/healthz
curl -k --fail --silent --show-error https://127.0.0.1:9004/readyz
```
`ss` 结果必须是 `127.0.0.1:9004` 或 `[::1]:9004`,不能是 `0.0.0.0:9004`。
`/healthz` 只用于存活检查;返回 HTTP `200` 仅表示 Scert 进程和 HTTP 服务可响应。`/readyz` 才是生产就绪检查,安装、升级、恢复、配置变更、Nginx 切流和监控告警均必须以它为准。
`/readyz` 只有在以下条件全部满足时返回 HTTP `200`:
- 初始化已完成。
- DNS 凭据引用存在并且可解密。
- 已配置的 HTTP 通知和 SMTP 通知凭据可解密。
- 内部 TLS 证书和私钥存在、是普通文件且不是符号链接。
- 数据库连接检查成功。
失败时返回 HTTP `503`,原因码不包含完整敏感信息引用:
| 原因码 | 处理要求 |
| --- | --- |
| `setup_incomplete` | 完成初始化流程。 |
| `dns_credential_missing` | 通过管理页面配置 DNS Provider 并完成在线 API 测试。 |
| `secret_store_unavailable` | 检查 `master.key`、`secrets.json` 和配置目录权限。 |
| `credential_unavailable` | 重新录入真实 DNS、HTTP 通知或 SMTP 通知凭据;禁止写入假 Token 绕过。 |
| `tls_material_unavailable` | 检查内部 TLS 证书和私钥路径、文件类型与权限。 |
| `database_unavailable` | 检查 SQLite 文件、MySQL/PostgreSQL 连通性、加密凭据、TLS、账户权限和连接限制。 |
`/healthz` 返回正常而 `/readyz` 返回 `503` 时,服务只能用于故障排查,不能接收生产流量。
### 5.2 Nginx
生产 Nginx 对外通常只开放 `443/tcp`;如需 HTTP 跳转,再开放 `80/tcp`。Nginx 到 Scert 必须配置:
```nginx
proxy_ssl_server_name on;
proxy_ssl_name scert.example.com;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_ssl_verify_depth 3;
```
生产配置禁止 `proxy_ssl_verify off`。私有 CA 应使用 root 管理的独立 CA 文件。当前 `9003` 测试入口不得开放到公网。
## 6. 防火墙
生产建议:
| 端口 | 来源 | 用途 | 要求 |
| --- | --- | --- | --- |
| `22/tcp` | 管理网段 | SSH 运维和证书推送 | 限制来源地址,优先仅允许密钥认证 |
| `443/tcp` | 业务访问网段 | Nginx HTTPS | 正式生产入口 |
| `80/tcp` | 可选 | HTTP 到 HTTPS 跳转 | 不使用跳转时关闭 |
| `9004/tcp` | 无外部来源 | Scert 内部端口 | 只绑定回环,不创建放行规则 |
| `9003/tcp` | 仅开发测试网段 | 当前 Nginx 测试入口 | 禁止公网开放 |
云安全组和主机防火墙必须同时核对,不能只配置其中一层。
## 7. 备份
### 7.1 备份内容
当前 Scert 内置备份/恢复支持 SQLite、MySQL 和 PostgreSQL。PostgreSQL 使用官方工具,自动恢复仅支持原目标数据库且对象清单、所有者一致的场景,不支持空库灾难恢复或跨结构版本迁移。工具版本、严格 TLS、权限及集群级资源的保护要求见 [PostgreSQL备份恢复说明](PostgreSQL备份恢复说明.md)。各平台真实演练结果须单独核对,功能存在不代表三数据库完整生产验收。
完整备份包含:
- `scert.json`
- `master.key`
- `secrets.json`
- `scert.db`、`scert.sql` 或 `scert.pgdump`
- `certificates/`
- `manifest.json`
SQLite 使用 `VACUUM INTO` 创建一致性快照并执行 `PRAGMA quick_check`。清单记录相对路径、权限、大小和 SHA-256。日志和数据库审计记录默认保留 30 天;文件日志每天最多写入 5 MiB,超过后停止文件写入但保留标准输出日志。
SQLite 文件库的每条物理连接(包括扩容和重建)均设置 WAL 与默认 5000 毫秒忙等待;不会把最大连接数强行改成 1 来绕过并发问题。带截止时间的数据库调用在剩余时间不足 5 秒时缩短本次原生等待预算,执行结束后恢复默认值;覆盖普通/预处理执行、查询、事务启动和结果读取。配置恢复失败会淘汰连接,不自动重放业务 SQL。其余 DSN 参数保留,忙等待和日志模式由产品控制。
重要限制:没有截止时间的手动取消仍依赖原生驱动中断,本批持锁测试在取消后约 5 秒返回;较长截止时间调用中途手动取消也不能承诺立即退出当前忙等待。事务提交/回滚沿用驱动接口,本批不承诺任意 SQL 脚本整体原子性或所有取消路径立即终止。Windows SQLite 3.49.1 已验证双连接池、三子进程竞争和活动 WAL 快照,但不代表网络文件系统、Linux 服务重启、断电恢复、完整业务数据恢复或多实例生产部署已经验收。证据及未完成项见《构建版本与数据库支持矩阵》第十五节。
SQLite 恢复前必须停止 Scert 服务和所有外部数据库访问。恢复命令取得维护锁后,由 SQLite 自身合并旧 WAL 并切换到 DELETE 日志模式,关闭连接后确认日志已清理,再生成恢复前副本并替换主文件;不能手动删除 WAL/SHM 来强行通过。存在外部事务、孤立日志、非普通日志路径或无法完成模式切换时会拒绝恢复。服务下次正常打开数据库仍按产品配置启用 WAL。服务维护锁不能阻止不遵守该锁的外部程序在检查结束后重新访问数据库,因此维护期间必须持续停止这些程序。
源码 `6db5d7b` 的 Windows 隔离测试已验证异常退出后的恢复与失败回滚、当前业务表和关联、配置归属、用户密码、加密凭据、真实证书私钥及重复恢复;证据见支持矩阵第十六节。这不是历史业务升级、独立发行程序、真实服务重启、物理断电或外部 DNS/SSH 调用的验收证明。无法正常读取的损坏库应先人工隔离并保留整套主文件和日志,不绕过日志安全检查。
MySQL 账号和密码从加密数据库凭据引用读取,只在维护连接期间存在于内存,不写回普通配置或备份清单。恢复前固定当前可用账号用于快照、导入和失败回滚;数据库服务端账号本身的密码轮换仍需单独管理,恢复旧配置不能自动恢复数据库账户密码。
MySQL 完整备份先检查有效库级或全局 `SELECT`,不能用零散表级权限或过滤后的空清单证明对象完整。视图还要求有效 `SHOW VIEW`;失效视图或定义不可见时拒绝备份并保留原文件。视图按本库依赖排序,保留定义者、创建字符集和检查选项,不创建占位基础表,也不删除与视图同名的已有基础表。基础数据和例程先于视图,随后创建触发器、恢复外键检查,最后恢复事件;仍需管理员保证维护窗口内没有外部 DDL 或授权变化。
本批嵌套 `CHECK OPTION` 夹具的原始官方导出文件在官方客户端出现 1368;Scert 仅对严格识别、连续且闭合的官方最终视图块按依赖重排,块内 SQL 和输入文件保持不变。不跨业务语句、`USE` 或未知设置排序;执行对应块前核对数据库、SQL 模式与客户端编码。此能力不是任意 SQL 兼容承诺,也不是恢复失败后已执行 DDL 的原子回滚保证。账户、跨库依赖及定义者授权仍需管理员准备。验证范围、证据和限制见《构建版本与数据库支持矩阵》第十四节。
MySQL 自有备份已增加触发器导出。维护账户除读取表结构/数据外,还需对每张可见基础表具有可证明的有效 `TRIGGER` 权限;没有权限时,数据库可能隐藏触发器,Scert 会明确拒绝而不是报告不完整备份成功。即使业务当前没有触发器,也不能据此省略该可见权限。产品不会自动扩权;精确库级或表级授权由管理员审核配置,复杂且存在遮蔽的通配授权可能被保守拒绝。
MySQL 自有备份同时导出存储过程和函数。5.7 维护账户需对 `mysql.proc` 具有完整 `SELECT` 权限;8.0 需具有有效 `SHOW_ROUTINE`,或没有被当前库部分撤销限制的全局 `SELECT`。仅有库级 `EXECUTE`、`CREATE ROUTINE` 或元数据中看不到例程,不能证明完整定义可见;即使源库当前没有例程,检查仍会执行。8.0 支持通过已启用角色获得权限,不会自动启用角色或扩权。请优先由管理员评估专用维护账户及最小可见权限,不给业务账户照搬测试授权。
恢复时先写入所有表数据,再创建例程和触发器,恢复外键检查后最后创建事件,保留原定义者、SQL 模式和创建字符集;同名例程和事件会先删除再创建。目标账户需具备相应对象管理权限、数据库 `ALTER` 权限,并满足实际服务器对定义者和二进制日志的权限要求。不能照搬隔离测试账户的全局管理权限,也不能通过开启全局信任来绕过验证。
MySQL 自有备份已增加事件导出,保存计划、时区、启停状态和创建会话属性。维护账户必须具有可证明的有效全局或库级 `EVENT` 权限,即使当前看不到事件也不能省略;表级授权不能证明事件完整可见。已经到期且重新创建会被自动删除或改变启用状态的事件,以及无法验证时区的事件,会被明确拒绝,不覆盖已有备份。
Scert 恢复需要有效全局 `PROCESS` 权限以检查事件工作线程。请在维护窗口由管理员停止事件调度,等待工作线程自然退出,并防止其他会话重新开启调度或修改对象;仅将调度器设为 `OFF` 不代表已有工作线程已经退出。产品不会自行修改全局调度器、终止线程或扩大权限。调度器为 `ON` 且目标库已有启用事件,或导入内容可能启用事件时,Scert 会在执行首条恢复语句前拒绝;全部事件禁用且没有运行线程的情况不受此项限制。工作线程识别会保守拒绝其他处于 `Connect` 状态的连接。
事件恢复后发现自动删除、自动禁用等影响对象完整性的警告时,Scert 会停止后续语句并报告失败,但不承诺回滚已经执行的 DDL。使用官方 MySQL 客户端导入时不会执行 Scert 的预检,管理员必须自行落实上述维护窗口、检查警告并核验对象、计划、时区及启停状态,完成核验后再恢复调度。
自有导出对视图及完整表清单的支持尚未补齐;例程和事件的 UTF-8、Latin-1 指定场景不代表任意字符集、SQL 模式或跨服务器定义者迁移通过。成功恢复后还原会话属性和源库数据库排序规则;中途失败的 DDL 原子回滚及排序规则回退仍需验证。不会清除备份之外的额外目标例程或事件,也不恢复数据库账号授权。例程历史证据见《构建版本与数据库支持矩阵》第十一、十二节;事件实现及正式 Go 测试已纳入代码,但不能据此宣布完整 MySQL 灾难恢复或生产部署验收通过。
### 7.2 停服备份
```bash
sudo systemctl stop Scert
sudo -u Scert /scert/scert --config /scert/conf/scert.json backup
sudo systemctl start Scert
```
程序会获取 `/scert/data/scert.lock` 跨进程维护锁。即使存在维护锁,生产流程仍必须停服,因为证书目录还可能被外部部署工具修改。
备份目录必须保持 `0700`,并复制到加密、离线或不可变存储。`manifest.json` 不是数字签名,不能替代备份介质权限、异地副本和访问审计。
## 8. 恢复
恢复前先复制当前完整数据目录和证书目录到受保护位置,然后执行:
```bash
sudo systemctl stop Scert
sudo -u Scert /scert/scert --config /scert/conf/scert.json \
restore --input /scert/backups/scert-YYYYMMDD-HHMMSS
sudo systemctl start Scert
```
恢复会拒绝:
- 缺少或被篡改的清单。
- 符号链接、特殊文件、异常权限、大小或 SHA-256。
- 跨配置目录、数据目录、证书目录、备份目录或数据库目标恢复。
- 无法解密的敏感配置引用。
- 主服务或另一个维护任务持有进程锁。
恢复前副本使用 `*.before-restore-YYYYMMDD-HHMMSS` 命名。失败时程序会尝试整体回滚;完成后必须验证健康接口、登录、域名列表、证书读取、SSH 推送和 Nginx HTTPS。
## 9. SSH 与证书推送
`192.168.2.4` 仅作为推送目标,不安装 Scert。每台主机、每次配置都必须生成随机公钥名称:
```text
/ssl/ssh/用户名+scert-随机值
```
验收要求:
- 首次连接人工核对 SSH 主机指纹。
- 主机指纹变化时拒绝连接,禁止自动接受新指纹。
- `cert.pem`、`fullchain.pem` 权限为 `0644`,`privkey.pem` 为 `0600`。
- 使用临时文件和原子重命名替换证书。
- Nginx 配置测试成功后才执行 reload。
- 推送、校验或 reload 失败时恢复旧证书。
- 临时私钥、密码、Token 和完整连接串不得写入日志。
## 10. 监控与日常检查
建议至少监控:
- `/healthz` 状态和响应时间。
- `/readyz` 生产就绪状态;连续返回 `503` 时停止切流并立即告警。
- systemd 服务状态、重启次数和退出码。
- 证书剩余有效期;默认续期阈值为 6 天,3 天进入紧急状态。
- 证书申请、部署、校验和通知任务失败数量。
- 文件系统剩余空间、SQLite/MySQL/PostgreSQL 可用性和备份最后成功时间。
- Nginx 5xx、上游 TLS 校验失败和 SSH 主机指纹变化。
常用命令:
```bash
sudo systemctl status Scert --no-pager -l
sudo journalctl -u Scert --since "1 hour ago" --no-pager
sudo ss -lntp | grep -E ':(443|9003|9004)\b'
sudo -u Scert /scert/scert --config /scert/conf/scert.json status
```
日志输出不得包含 DNS Token、SMTP 密码、HTTP 通知密钥、SSH 私钥、超级管理员密码或会话 Cookie。
### 10.1 共享主机测试资源隔离
启动实机演练前检查 `MemAvailable`、Swap、`/proc/pressure/memory`、磁盘空间和内核 OOM 日志,确认既有业务服务正常。多个项目应协调测试窗口,避免并发构建或启动数据库集群。
测试使用独立目录、全新数据库和回环端口,不清空既有业务库。通过 systemd 临时单元将测试程序及其子进程放入同一 cgroup,设置内存、CPU、进程数和总运行时间限制,并保留 `KillMode=control-group`。资源限制须按场景容量制定;小数据演练的限制不能直接作为生产配置。
超时或 SSH 失联后,先检查主机和共享服务,再核对本轮 PID、集群目录及端口,只停止确认属于本轮的测试资源。保留产物,不通过重启共享数据库、扩大权限或单纯延长超时掩盖故障。区分全局 OOM 与 `CONSTRAINT_MEMCG`,不要把其他项目的受限测试失败记为 Scert 的结果。
## 11. 当前外部验收边界
以下项目必须有真实外部环境和合法凭据才能完成,不能由本地自动化测试替代:
- 真实 DNS Provider API 的最小权限凭据与在线写入/清理验证。
- 合法域名的 Let’s Encrypt Production 申请、续期和速率限制处理。
- MySQL 5.7 与 8.0 的真实备份、恢复和失败回滚。
- PostgreSQL 目标环境的真实连接、迁移、权限、业务与恢复演练;空库灾难恢复及跨版本迁移仍不属于内置自动恢复支持范围。
- 新 IP 初始化在最小权限 systemd 下的防火墙行为、临时证书身份核对、浏览器页面及正式入口切换。
- Windows Service 安装、升级、开机启动、停止和 ACL。
- 公网生产 Nginx、真实证书链和最终业务访问。
这些外部项未完成时不能声明完整生产准入。2026-09-17 已从干净提交生成 Linux 候选包,当前实机进展见 [Linux生产流程测试记录](Linux生产流程测试记录.md)。Linux + SQLite 的受控试运行同样需要当前版本的目标主机验证,不得复用旧版本结论或把隔离测试等同于正式切流。