Files
opsx-vpn/docs/specs/SDD-005-nginx-live-public-entry.md
T

67 lines
6.2 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.
# SDD-005:Nginx 公网入口保存后即时生效
| 字段 | 内容 |
|---|---|
| 版本 / 变更级别 | 0.1 / S3 |
| 设计状态 | 已形成 |
| 实现状态 | 已实现并部署;本地 Go 测试、前端构建及生产 HTTPS 回归通过,生产热切换未演练 |
| 负责人 / 日期 | opsx-vpn / 2026-10-26 |
| 关联需求 | 在 Nginx 模式修改 HTTP/HTTPS 公网入口,无须重启管理进程;管理端口保持 18080 |
| 批准状态 | 用户提出修改 |
## 1. 背景、目标与范围
- 现状:`api.setTLSDomain` 仅调用 `tlsservice.ConfigurePublicEntry` 写入 `data/tls-*`;`tlsservice.Status` 比较启动配置并要求重启。`nginxgateway.RefreshAuthEntry` 只能刷新同域名;页面先保存域名再另存模式,显示不准确的“重启后监听 80/443”。
- 目标:已运行 Nginx 模式、已有托管站点时,保存协议、域名或端口会重写托管 Nginx 配置、`nginx -t` 和 reload,成功后更新内存配置及状态,返回即时生效;入口始终反代现有 18080 管理服务。
- 边界:首次安装/启用站点依旧单独执行并提供申请证书的日志;Go autocert 模式和入口模式切换仍需重启,因为涉及 Go 监听器。生产当前 HTTPS 入口不自动切换到 HTTP。
- 保留:原 HTTP-01 路由白名单、已有 OpenVPN/OIDC 回调、证书路径及未提交文件。
## 2. 需求与约束
- FR-01:已启用 Nginx 站点时保存公网入口即时更新站点及状态,不改变应用管理监听端口。
- FR-02:失败时包括缺失/过期目标证书、端口冲突、`nginx -t`/reload 或配置持久化失败,恢复旧站点和旧状态并返回具体错误。
- FR-03:首次配置但尚无托管站点时,保存后提示“待启用站点”,点击启用后无须重启;切换进程入口模式明确提示重启。
- FR-04:运行中的 OpenVPN OIDC 使用旧公网回调时,禁止修改会使其回调失效的入口地址。
- FR-05:启动时若历史保存配置与已启用的 Nginx 站点不符,保持实际站点与身份 issuer 一致,展示待应用配置,而非在启动时静默覆盖站点。
- NFR-01:只允许管理员修改;拒绝覆盖不属于本应用的站点;更新操作与证书上传/身份路由刷新互斥。
## 3. 架构与方案
保存接口按运行模式分支:Nginx 托管站点先校验新域名证书与活跃 OIDC 引用,在锁内生成站点、备份原内容、原子替换、测试及 reload,再持久化公网配置并更新 `tlsservice` 内存;失败恢复原站点。未启用站点只保存草稿;启用站点成功后更新内存。启动时解析现有托管站点,与持久化配置不一致则使用实际入口作为运行态并保持原站点,页面显示待应用配置。Go 模式原有需重启语义保留。前端按 `restart_required`、`site_activation_required` 和 `applied` 分别提示。
## 4. 接口、数据与配置契约
- `PUT /api/system/tls/domain` 请求体仍为 `{domain, scheme, port}`,响应增加 `applied` 与 `site_activation_required`;模式接口不变。
- `GET /api/system/tls` 继续提供配置/运行状态;已完成热更新时 `restart_required=false`。
- 没有数据库迁移或新配置文件。`VPN_TLS_*` 环境变量仍优先且不能被 UI 覆盖。
## 5. 风险与验收
| 风险或失败场景 | 防护 / 恢复 | 可观察信号 |
|---|---|---|
| 新入口证书不可用 | 拒绝 HTTPS 切换,旧站点不动 | 4xx 及原证书继续可用 |
| Nginx 校验/重载失败 | 恢复站点并重新 reload;返回错误 | 5xx、`nginx -t`、健康检查 |
| 已连接 OIDC 专线回调旧地址 | 拒绝修改公网地址 | 409 与原专线可用 |
| 旧版本保存的 HTTP 草稿在升级重启后覆盖 HTTPS | 启动时先对比实际 Nginx 站点,不一致时采用站点运行态 | 公网仍提供旧 HTTPS,日志提示草稿待应用 |
| 旧站点归属不明 | 拒绝覆盖 | 错误提示;人工检查 |
| AC | 对应需求 | 前置与操作 | 预期结果 | 验证方式 | 结果 |
|---|---|---|---|---|---|
| AC-01 | FR-01, NFR-01 | Nginx HTTPS 已启用,保存相同域名/端口 | 不重启,健康检查可用,状态即时同步 | 单测、实机回归 | 状态更新单测通过;线上保存操作未执行 |
| AC-02 | FR-02 | 无证书、无效端口或模拟 reload 失败 | 不丢失旧入口、状态不变化 | 单测与配置检查 | 回滚单测通过;在线异常待验证 |
| AC-03 | FR-03 | 尚未启用站点保存,再启用 | 不要求重启;Go 模式仍准确提醒 | 单测、前端构建 | 本地通过;首次启用实机待验证 |
| AC-04 | FR-04 | 有 OIDC 专线运行时修改回调根地址 | 拒绝并保留原站点 | API 模块测试 | 本地拒绝与停用后放行测试通过;在线拒绝路径待验证 |
| AC-05 | FR-05 | 已保存 HTTP 草稿,运行站点仍为 HTTPS | 重启后不重写站点,运行态 issuer 仍为 HTTPS | 解析单测、运行态单测、实机回归 | 本地测试通过;生产历史草稿未再次演练 |
## 6. 发布与恢复
本地 Go 测试、前端构建通过后提交。若部署,先备份程序/数据库和托管站点,保持 HTTPS 现状,先构建前端和后端,再切换管理进程。核验公网 HTTPS、OIDC 发现、`nginx -t`、OpenVPN 进程与 18080 健康。故障时恢复旧程序和站点并 reload;不删除证书或 `data/`。不计划在线演练切换为 HTTP。
2026-10-26 发布回归:旧版在 14:19 已保存 HTTP:28080 草稿,首次升级重启时启动同步按该草稿将 Nginx 切至 28080,导致 HTTPS:443 暂时不可达。保留 HTTP 配置与站点的 `/tmp` 副本后,将数据配置及站点恢复 HTTPS:443、重新加载 Nginx 并重启管理服务;随后补充运行站点与草稿比对保护,部署提交 `97da0a5`。最终 `nginx -t`、公网健康、登录页及 HTTPS OIDC issuer 正常,80/443 与 18080 监听正常,OpenVPN 和认证组件存活。未执行生产 HTTP 切换或在线保存操作。
## 7. 待决问题
| 问题 | 是否阻塞 | 推荐方案 |
|---|---|---|
| 新域名尚无证书时是否自动签发 | 不阻塞即时更新已配置站点 | 拒绝带故障风险的热切换,先通过证书流程准备证书;未来单独设计零停机多域名签发 |