diff --git a/deploy/nginx/Scert.conf.example b/deploy/nginx/Scert.conf.example new file mode 100644 index 0000000..875fc54 --- /dev/null +++ b/deploy/nginx/Scert.conf.example @@ -0,0 +1,54 @@ +# 部署前替换管理域名、证书路径和端口占位符,不能直接加载本文件。 +# 管理域名由部署环境决定,不在应用代码中固定。 +server { + listen __HTTP_PORT__ default_server; + listen [::]:__HTTP_PORT__ default_server; + server_name _; + return 404; +} + +server { + listen __HTTP_PORT__; + listen [::]:__HTTP_PORT__; + server_name __MANAGEMENT_HOST__; + return 308 https://__MANAGEMENT_HOST__:__HTTPS_PORT__$request_uri; +} + +server { + listen __HTTPS_PORT__ ssl default_server; + listen [::]:__HTTPS_PORT__ ssl default_server; + server_name _; + ssl_reject_handshake on; +} + +server { + listen __HTTPS_PORT__ ssl; + listen [::]:__HTTPS_PORT__ ssl; + server_name __MANAGEMENT_HOST__; + ssl_certificate __FULLCHAIN_PATH__; + ssl_certificate_key __PRIVATE_KEY_PATH__; + ssl_protocols TLSv1.2 TLSv1.3; + client_max_body_size 64m; + access_log /var/log/nginx/scert-access.log combined; + error_log /var/log/nginx/scert-error.log warn; + + location / { + proxy_pass https://127.0.0.1:__UPSTREAM_PORT__; + proxy_http_version 1.1; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-Host $http_host; + proxy_set_header X-Forwarded-Port __HTTPS_PORT__; + proxy_set_header Connection ''; + proxy_ssl_server_name on; + proxy_ssl_name __MANAGEMENT_HOST__; + proxy_ssl_verify on; + proxy_ssl_verify_depth 3; + proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt; + proxy_connect_timeout 5s; + proxy_read_timeout 180s; + proxy_send_timeout 90s; + } +} diff --git a/doc/Linux生产流程测试记录.md b/doc/Linux生产流程测试记录.md index 560d71a..265d557 100644 --- a/doc/Linux生产流程测试记录.md +++ b/doc/Linux生产流程测试记录.md @@ -1,5 +1,63 @@ # Linux 生产流程测试记录 +## 当前结论:管理入口接续验收 + +以下为 2026-09-17 23:16 至 23:35 的接续结果,覆盖后文早期阶段关于域名未确认、初始化未完成和入口未部署的旧状态。不能将各阶段的通过项混为完整生产验收。 + +### 需求与任务状态 + +已确认管理域名可配置,本次使用 `web.apmmk.cn`,Nginx HTTP 8003 跳转 HTTPS 8004,上游为 `https://127.0.0.1:9004`。实际仓库为 `D:\Desktop\Scert`,不使用已不存在的旧目录。 + +- [✓] 复核真实初始化与正式证书,上游严格 TLS 校验下就绪。 +- [✓] 独立 Nginx 站点部署、主机防火墙放行、未知域名拒绝、HTTP 跳转及双层 TLS 校验。 +- [✓] 隧道访问线上站点的桌面浏览器登录、刷新会话、退出及接口鉴权测试。 +- [✓] 六组跨域写入拒绝、退出后旧 Cookie 重放拒绝。 +- [✓] Scert 开机自启已启用;未重启共享主机,不能视为重启演练通过。 +- [x] 通用反代配置样例和部署说明已补充,等待整体生产复审。 +- [!] 公网 8003/8004 在独立 Linux 主机访问超时,需核对云安全组或上游网络。 +- [!] 管理证书未进入续期队列,且尚无上游 TLS 与 Nginx 的证书更新生效机制。 +- [ ] 真实目标机证书推送、完整故障回退、通知送达与容量验收仍需完成。 + +### 已核对的运行版本 + +正式程序来自已推送提交 `b6d1b96426437df412b508e2bfff06b1dde02871`。其阿里云修复使用限定域名及精确 TXT 记录查询,以兼容当前 RAM 权限,同时对 DNS 主机名进行不区分大小写比较,记录 ID 和 TXT 内容仍严格匹配。本阶段没有再次替换正式二进制。 + +23:30 重新计算正式程序 `/scert/scert` 的 SHA-256 为 `f5b08bf0fb88f7b19281e91f942aa2995866f96420e422c015890b841bae6366`;升级前快照 `/var/backups/scert-pre-dns-b6d1b96/snapshot.tar.gz` 的摘要为 `5dae6d9444768243a9440e69dfaf41870cbbc2a85702d2d8923579763ca77715`。 + +当前管理证书为 Let's Encrypt YR2 签发,主题 `web.apmmk.cn`,有效期截止 `2026-12-16 14:14:04 UTC`。上游及 Nginx 探测均使用公共 CA 和主机名验证,没有使用跳过证书验证选项。 + +本阶段延续已完成初始化的独立测试数据集,没有清空数据库或重跑初始化。管理员密码仅保留在管理机 root 可读的受限凭据文件中,不进入代码、报告和截图。 + +### 反向代理部署 + +新增 `/etc/nginx/conf.d/scert-apmmk.conf`,保留 `/etc/nginx/nginx.conf` 与 `smail.conf`,部署前后内容摘要一致。配置备份位于 `/var/backups/scert-nginx-20260917-2320-v2`。第一次配置因本机参数传递导致空字符串引号损坏,被 `nginx -t` 拦截并移出有效加载目录,未重载;修正后语法检查成功才平滑重载。 + +8003 对已配置域名返回 308,示例路径 `/login?acceptance=1` 正确跳转至 `https://web.apmmk.cn:8004/login?acceptance=1`;未知域名返回 404。8004 的未知 SNI 拒绝握手。已配置域名通过 `proxy_ssl_verify on` 和 `proxy_ssl_name web.apmmk.cn` 验证 9004 上游,保留 `Host $http_host` 中的外部端口。 + +UFW 新增 TCP 8003、8004 的 IPv4/IPv6 入站规则;9004 仍只监听回环地址。`Scert.service` 此前为 disabled,现已执行 enable;Nginx 原已启用。没有重启 Scert、Smail、MySQL 或主机。 + +23:30 状态:Scert PID `576928`、重启零;Nginx 主进程 PID `575746`;Smail PID `574584`、重启零;MySQL PID `549584`、重启一。应用进程均与本阶段开始时一致。 + +### 浏览器与安全测试 + +本轮没有可调用的浏览器 MCP,使用独立 Playwright Chromium 上下文作为替代。新建上下文并禁止 Service Worker,不复用旧缓存。通过本机回环 SSH 隧道连接线上 Nginx 8004,浏览器 URL、TLS SNI 和证书校验仍使用真实管理域名;没有忽略 HTTPS 错误。这是线上应用测试,不是公网入口测试。 + +通过真实表单登录、页面跳转、刷新后会话保持、设置和用户等只读接口访问、退出、退出后 401 检查。Cookie 为 `Secure`、`HttpOnly`、`SameSite=Lax`、路径 `/`。1440 和 1024 桌面宽度没有横向溢出、损坏图片或页面脚本错误;截图仅代表这些桌面尺寸,不代表移动端验收或完整视觉复审。 + +本地证据目录 `.runtime/apmmk-browser-20260917-2330/` 含 `result.json`、`login-1440.png`、`dashboard-1440.png`、`dashboard-1024.png`,保持 Git 忽略。脚本不把管理员密码或 Cookie 写入结果。 + +远端协议脚本 `apmmk_security_acceptance.py` 使用严格 TLS 测试三个错误 Origin:异域、缺失外部端口、错误协议。对设置写入及退出各测试一次,共六次均为 403,且原会话仍有效;正常退出后重放原 Cookie 为 401。 + +100 次就绪请求、并发四,全部返回正常;中位约 28.57 毫秒、P95 约 38.91 毫秒。测试前主机可用内存约 779 MiB、Swap 使用约 155 MiB。这仅是短时只读探测,不替代签发、部署、数据库写入或持续负载的容量测试。 + +### 当前阻塞与续期风险 + +Windows 本机 DNS 返回代理软件虚拟地址 `198.18.0.51`,默认访问失败,不能据此单独归因服务器。另从目标机 `8.137.23.95` 只读访问管理机公网,两个端口均连接超时;指定真实 IP 的 HTTPS 再测也超时。同期管理机监听与 UFW 正常,短时抓包未捕获该外部连接。当前证据提示云安全组或其他上游网络限制,尚未读取云安全组规则,不能断言已定位唯一原因。本次在目标机只执行网络探测,没有部署、清库或重启操作。 + +续期 API 实际返回 `checked=0`、`selected=0`;域名列表为空。源码核对表明 `IssueForSetup` 只保存管理证书,而当前调度器遍历托管域名仓库;HTTP 服务调用静态 `ListenAndServeTLS`,Nginx 也引用固定版本路径。因此证书有效不等于管理证书能够自动续期。必须补齐续期调度、证书事务切换、双层 TLS 更新、失败保留旧证书和恢复验证后再解除该门槛。 + +## 历史阶段记录 + ## 范围与任务状态 2026-09-17 在管理机 `47.108.78.12` 执行当前版本的受控测试。`8.137.23.95` 仅为推送测试机,本记录不包含对它的操作。不运行固定安装器,不切换正式服务,不清空既有数据库,不修改共享 Nginx 或业务证书。 diff --git a/doc/管理入口反向代理部署.md b/doc/管理入口反向代理部署.md new file mode 100644 index 0000000..8e3ccb4 --- /dev/null +++ b/doc/管理入口反向代理部署.md @@ -0,0 +1,52 @@ +# 管理入口反向代理部署 + +## 适用范围 + +管理域名由部署者指定,不固定为测试域名。独立站点模板位于 `deploy/nginx/Scert.conf.example`,适用于已完成初始化并取得正式管理证书的 Linux 服务。 + +当前模板不提供管理证书自动续期、证书路径切换或服务重载机制。完成这三项的实现和故障测试之前,不应据此宣布无人值守生产部署验收通过。 + +## 当前测试参数 + +| 占位符 | 本次测试值 | +| --- | --- | +| `__MANAGEMENT_HOST__` | `web.apmmk.cn` | +| `__HTTP_PORT__` | `8003` | +| `__HTTPS_PORT__` | `8004` | +| `__UPSTREAM_PORT__` | `9004` | +| `__FULLCHAIN_PATH__` | `/ssl-scert-acceptance/web.apmmk.cn/single/20260917-V1.0/fullchain.pem` | +| `__PRIVATE_KEY_PATH__` | `/ssl-scert-acceptance/web.apmmk.cn/single/20260917-V1.0/key.pem` | + +应用配置应保持 `server.https_mode=proxy`、回环监听 `127.0.0.1:9004`,并设置 `server.proxy_https_port=8004`。修改管理域名时,应同步调整应用域名、DNS、证书、Nginx 的 `server_name`、跳转地址和 `proxy_ssl_name`,不能只更改浏览器入口。 + +## 部署流程 + +1. 核对现有监听端口、Nginx 配置和同机服务。保留主配置及其他项目站点,不覆盖共享站点。 +2. 备份配置并核对权限。使用模板生成独立站点,逐项替换英文占位符;检查没有残留占位符。 +3. 确认证书覆盖管理域名且未过期,私钥受限。上游必须通过公共 CA 与主机名校验,不允许关闭 `proxy_ssl_verify`。 +4. 执行 `nginx -t`,成功后才执行 `systemctl reload nginx`。检查失败时保留失败文件用于审查,但从有效配置加载目录移出,不重载服务。 +5. 在主机防火墙及云安全组分别放行所需的 TCP 入口。本次为 `8003`、`8004`;管理后台应按实际使用范围限制来源。不要将上游 `9004` 对公网开放。 +6. 核对 `systemctl is-enabled Scert.service nginx.service`。启用开机自启不等于完成主机重启演练。 + +`Host $http_host` 用于保留外部非标准端口。HTTP 跳转目标使用固定的配置域名,不使用客户端 Host 作为跳转目标;未知 HTTP 域名返回 404,未知 TLS SNI 拒绝握手。 + +## 验收流程 + +服务器内先验证 Nginx 与上游,不跳过 TLS 校验: + +```sh +curl --noproxy '*' --resolve web.apmmk.cn:8004:127.0.0.1 \ + --fail --show-error https://web.apmmk.cn:8004/readyz +curl --noproxy '*' --resolve web.apmmk.cn:8003:127.0.0.1 \ + --head 'http://web.apmmk.cn:8003/login?acceptance=1' +``` + +预期分别是就绪响应和 308 跳转,跳转保留路径及查询参数。随后必须从独立公网主机与真实浏览器验证,不使用 `--resolve`、SSH 隧道或跳过证书校验掩盖入口故障。 + +桌面浏览器验收包括登录、刷新会话、退出后访问拒绝、静态资源和不同桌面宽度;协议验收包括 Cookie 安全属性、跨域写入拒绝和退出后的旧 Cookie 重放拒绝。使用新浏览器上下文,不复用其他项目缓存或会话。 + +若必须借助 SSH 隧道继续应用测试,应明确标记为隧道测试;即使浏览器全部通过,也不能等同公网部署通过。清理测试环境时只操作确认过的独立测试数据库,不清空共享服务器上的其他项目数据库。 + +## 剩余门槛 + +2026 年 9 月 17 日的具体结果见 `Linux生产流程测试记录.md`。本次 Nginx 站点内网验证成功,但独立 Linux 主机访问两个公网端口超时,尚需核对云安全组或上游网络。管理证书自动续期、更新后的双层 TLS 生效、故障回退以及真实目标机部署均需继续完成,不能将 `readyz=200` 作为完整验收结论。