Files
lisglosips/docs/SERVER_B_WEB_RUNTIME_RUNBOOK.md
T

174 lines
6.3 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.
# Server B Web 运行时 Runbook
本文记录 S05 在 Server B 上建立的 Node.js、pnpm、Nginx、systemd 与开发 TLS 基线。当前环境是本地 KVM 开发环境,不是阿里云生产环境。
## 1. 固定版本
| 组件 | 版本 | 管理方式 |
| --- | --- | --- |
| Node.js | `v22.22.2` / Debian 包 `22.22.2-1nodesource1` | NodeSource 22.x`apt-mark hold` |
| Corepack | `0.34.6` | Node 全局工具 |
| pnpm | `10.33.0` | 全局固定版本;项目应再用 `packageManager` 固定 |
| Nginx | `1.24.0-2ubuntu7.12` | Ubuntu 24.04 security/updates`apt-mark hold` |
Node.js 22 当前属于 LTS 线。固定包在升级前必须先核对 Node/Nginx 安全公告、NestJS/Prisma 兼容性并完成回归测试。
版本记录:`/etc/lisglosips/web-runtime-versions.env`
## 2. 目录与发布模型
```text
/opt/lisglosips/
├── releases/
│ └── s05-placeholder-20260620/
│ ├── public/index.html
│ └── server.mjs
└── current -> /opt/lisglosips/releases/s05-placeholder-20260620
```
- 发布目录由 `root:lisglosips` 持有,程序只读。
- `current` 必须是指向完整 release 的符号链接。
- 正式发布先写入新 release,完成校验后再原子切换 `current`
- 不允许直接在 `current` 指向的 release 内在线修改代码。
- systemd 可写状态目录为 `/var/lib/lisglosips`,运行目录为 `/run/lisglosips`
## 3. systemd 服务模板
模板:`/etc/systemd/system/lisglosips@.service`
实例环境文件:`/etc/lisglosips/<实例名>.env`,权限必须为 `0640 root:lisglosips`。当前实例:
```text
lisglosips@api.service -> /etc/lisglosips/api.env
```
模板默认使用 `lisglosips` 系统用户,启用只读系统、私有临时目录、空 capability、设备隔离和内核保护。后续 Worker 如需写录音目录,应使用实例 drop-in 精确增加 `ReadWritePaths`,不要放宽整个模板。
常用命令:
```bash
sudo systemctl status lisglosips@api
sudo systemctl restart lisglosips@api
sudo journalctl -u lisglosips@api -n 100 --no-pager
sudo systemd-analyze security lisglosips@api.service
```
## 4. Nginx 路由
| 路径 | 行为 |
| --- | --- |
| `/` | `/opt/lisglosips/current/public` 静态站点,支持 SPA fallback |
| `/healthz` | 反向代理到 `127.0.0.1:3000` |
| `/api/` | API 代理,单 IP `20 r/s`、burst 40 |
| `/api/auth/login` | 登录专用限制,单 IP `5 r/min`、burst 3 |
| `/_recordings/` | 仅供 `X-Accel-Redirect` 内部访问,外部请求返回 404 |
关键文件:
```text
/etc/nginx/conf.d/lisglosips-global.conf
/etc/nginx/sites-available/lisglosips.conf
/etc/nginx/snippets/lisglosips-proxy.conf
/etc/nginx/snippets/lisglosips-security-headers.conf
/etc/nginx/snippets/lisglosips-tls.conf
```
应用仅监听 `127.0.0.1:3000`。Nginx 监听 80/443,但 nftables 仅允许已登记管理端访问 443;开发阶段没有对外开放 80。
配置变更:
```bash
sudo nginx -t
sudo systemctl reload nginx
```
## 5. 开发 TLS
开发 CA 和证书位于:
```text
/etc/lisglosips/pki/ca/lisglosips-dev-ca.crt
/etc/lisglosips/pki/ca/lisglosips-dev-ca.key
/etc/lisglosips/pki/certs/server.crt
/etc/lisglosips/pki/private/server.key
```
CA 私钥为 `0600 root:root`,服务器私钥为 `0640 root:www-data`。证书 SAN 包含 `lisglosips.local``yanzi``100.90.90.91``127.0.0.1`
重新签发开发证书:
```bash
sudo /usr/local/sbin/lisglosips-issue-dev-cert
sudo nginx -t
sudo systemctl reload nginx
```
本机公有 CA 副本保存在 `.codex-private/tls/lisglosips-dev-ca.crt`,不得把 CA 私钥复制出 Server B。Windows 使用私有 CA 测试时,因开发 CA 不发布 CRL,curl 需附加 `--ssl-no-revoke`;这不会关闭证书链、主机名或签名校验。
迁移阿里云后必须替换为正式域名证书,并完成:
1. 把证书和私钥放入受控 Secret 路径。
2. 更新 `lisglosips-tls.conf`
3. 将 HSTS 从开发值 `300` 调整为生产值,建议先观察再提升至 `31536000`
4. 验证自动续期、续期失败告警和回滚证书。
5. 开放 80 仅用于 ACME/跳转,或使用 DNS-01 后继续关闭 80。
## 6. 健康检查
```bash
curl --fail http://127.0.0.1:3000/healthz
curl --fail --cacert /etc/lisglosips/pki/ca/lisglosips-dev-ca.crt \
https://127.0.0.1/healthz
sudo ss -lntp | grep -E ':(80|443|3000)\b'
sudo systemctl --failed
```
预期:
- `/healthz` 返回 `status=ok`
- 3000 仅出现在 `127.0.0.1`
- 443 由 Nginx 监听。
- 首页响应包含 HSTS、CSP、X-Frame-Options、X-Content-Type-Options 和 Permissions-Policy。
- TLS 1.2/1.3 可用,TLS 1.1 被拒绝。
## 7. 新版本发布
```bash
release="2026xxxxTxxxxxxZ"
sudo install -d -o root -g lisglosips -m 0750 "/opt/lisglosips/releases/$release"
# 将已经构建和校验的产物放入新 release。
sudo chown -R root:lisglosips "/opt/lisglosips/releases/$release"
sudo find "/opt/lisglosips/releases/$release" -type d -exec chmod 0750 {} +
sudo find "/opt/lisglosips/releases/$release" -type f -exec chmod 0640 {} +
sudo ln -sfn "/opt/lisglosips/releases/$release" /opt/lisglosips/current
sudo systemctl restart lisglosips@api
sudo nginx -t && sudo systemctl reload nginx
```
发布后必须检查内部健康、HTTPS 健康、日志、应用端口监听和前端静态文件。数据库迁移从 S08 起必须在切换 `current` 前按迁移 Runbook 执行。
## 8. 回滚
应用回滚:把 `current` 指回上一 release,重启应用并检查 HTTPS 健康。
```bash
sudo ln -sfn /opt/lisglosips/releases/<previous> /opt/lisglosips/current
sudo systemctl restart lisglosips@api
```
S05 变更前备份:
```text
/var/backups/lisglosips-s05/20260620T123432Z
```
其中 `pre-change.tar.gz` 包含变更前应用与配置,`SHA256SUMS` 用于恢复前校验。恢复 Nginx/systemd 配置后必须执行 `nginx -t``systemctl daemon-reload`,再重启对应服务。卸载 Nginx或解除包固定不是常规回滚动作,只有确认恢复目标需要时才执行。
## 9. 已知事项
- NodeSource 仓库在本地代理链路上偶尔出现 TLS 握手中断;现有索引和已安装包可用。升级前必须先确认仓库恢复并校验候选版本。
- 当前证书仅供开发,不能用于阿里云生产。
- 80 已监听但被 nftables 拒绝;生产是否开放取决于证书签发方案。
- 当前 API 是 S05 无依赖占位服务,S07 后端骨架完成后替换。