SDD-003:域名与 HTTPS 证书管理
| 字段 |
内容 |
| 版本 / 变更级别 |
0.1 / S3(证书私钥、网络入口及生产代理配置) |
| 设计状态 |
Draft |
| 实现状态 |
应用内 ACME、域名设置与管理员状态页已实现,本地构建/单测通过;生产端口/证书待部署验证 |
| 负责人 / 日期 |
待指定 / 2026-10-21 |
| 关联需求 |
test-link.appx365.com 使用 HTTP-01 自动签发和续期;管理后台提供域名及证书页面;桌面客户端可使用 HTTP 或 HTTPS,并在设置中填写地址 |
| 批准状态 |
用户要求开发与评估;生产入口切换以部署核验为准 |
1. 背景、目标与范围
- 当前行为:后端路由在
:18080 提供管理站点和 API;部署文档仅描述外置 Nginx/Let's Encrypt 方案,没有集成证书状态页面。桌面 URL 校验拒绝远端 HTTP,地址位于概览页。
- 2026-10-21 只读核对:
test-link.appx365.com 解析到 121.4.111.208;服务器没有发现 Nginx、Certbot,80/443 未被监听。
- 本次目标:使用项目已有的 Go
autocert 依赖,在现有 Gin 进程中提供公网 80/443、HTTP-01 自动签发/续签;管理 API 和页面展示域名及缓存证书状态;桌面将地址放在设置中,接受 HTTP(提示明文风险)。单域名场景无需 Nginx、Certbot 或额外的 gin-gonic/autotls 封装。
- 非目标:将证书私钥存到 SQLite/浏览器;允许任意命令、代理任意上游、公开认证服务内部端口;向桌面发放管理员 token;把 WireGuard 51820/UDP 交给 Nginx 代理。
- 保留行为:旧
:18080 管理界面与现有 VPN 专线不受证书签发流程影响;证书失败保持现有 HTTP 服务可用。
2. 需求与约束
- FR-01:管理员能查看当前域名、DNS、监听地址、证书颁发者/到期日;接口不返回私钥、登录凭据或证书正文。
- FR-02:服务端仅为管理员保存的域名或
VPN_TLS_DOMAIN 指定的单一有效域名签发(环境变量优先),ACME 使用该域名 HostWhitelist;首次 HTTPS 握手签发,证书与账号密钥持久缓存于 data/acme,禁止任意域名签发。
- FR-03:续签由
autocert.Manager 自动管理;重启后缓存证书由首次握手加载并继续续签,到期日由管理页显示;签发或续签失败保留已有 18080 HTTP 入口。
- FR-04:HTTP 80 通过
autocert.Manager.HTTPHandler 放行 HTTP-01,其他当前域名请求重定向 HTTPS;443 用同一 Gin handler 提供管理站点与 API。OIDC 认证入口若另设域名需另行设计其路由,不从后台域名假设回调。
- FR-05:桌面客户端服务端地址移到“设置”,支持完整 HTTP/HTTPS 根地址并允许保存;HTTP 展示风险提示,但健康检查可以执行。不保存账号和令牌。
- NFR-01:管理 API 仅
admin,域名符合严格 FQDN 白名单;私钥缓存目录权限 0700,不暴露证书缓存内容或触发任意命令。
- NFR-02:部署前核对 DNS、云安全组 TCP 80/443、端口占用、现有入口与回退;续签有可观测到期信息。浏览器页面与 Tauri 环境的 URL 校验一致。
3. 架构与方案
使用项目已存在的 golang.org/x/crypto/acme/autocert,无需额外 Gin 插件或依赖:管理员将域名保存到 data/tls-domain,重启后生效;VPN_TLS_DOMAIN 优先于文件配置,VPN_TLS_HTTP_ADDR / VPN_TLS_HTTPS_ADDR 可覆盖监听地址;未配置域名时完全保留旧启动行为。证书管理不写入业务数据库。首次公网 HTTPS 请求后才有真实缓存证书,管理页未签发前必须显示“等待首次访问”,不能声称证书已签发。HTTP 客户端输入只是用户选择;登录与设备令牌将来仍应推荐 HTTPS。
4. 接口、数据与配置契约
GET /api/system/tls 与 PUT /api/system/tls/domain 仅管理员可用,分别读取状态与保存单域名;状态返回当前/待启用域名、是否需重启、DNS、监听地址及 autocert 缓存证书的颁发者/到期日。没有手动签发按钮,首次 TLS 握手会触发签发。证书缓存位于 data/acme,不接收请求任意域名作为签发目标。
- 云安全组 TCP 80/443 与 DNS A 解析须对应当前服务器;
VPN_TLS_DOMAIN=test-link.appx365.com 生效时若端口占用,应用拒绝启动并保持旧进程可回滚。
- 桌面仅在本机保存不含凭据的服务端地址;只允许
http / https 和根地址,拒绝 URL 账号、查询、片段、非根路径;实际健康检查继续调用 /api/health。
5. 风险与验收
| 风险或失败场景 |
防护 / 恢复 |
可观察信号 |
| 域名指向错误或 80 不可达 |
不启用证书前先核对 DNS 和公网入站;失败保留旧 18080 |
ACME 错误日志、证书未缓存 |
| 80/443 端口占用 |
启动时先绑定两个端口,失败则终止新版进程并回退旧版 |
启动日志与端口监听 |
| 续签失败与证书过期 |
autocert 自动续签、到期日提示、缓存保留 |
证书到期信息与 ACME 日志 |
| 公网 HTTP 管理凭据泄漏 |
HTTPS 默认推荐;明示 HTTP 风险;服务端切换后限制 18080 公网 |
HTTPS 可达、18080 仅可信入口 |
| AC |
对应需求 |
前置与操作 |
预期结果 |
验证方式 |
状态 |
| AC-01 |
FR-01, NFR-01 |
管理员/非管理员请求状态 |
仅管理员可查看,证书私钥不回传 |
路由权限检查;线上请求待验证 |
部分验证 |
| AC-02 |
FR-02, NFR-01 |
设置非法域名或端口占用 |
启动前拒绝,不向任意域名申请 |
域名/端口失败分支单测 |
已通过(本地) |
| AC-03 |
FR-03, FR-04, NFR-02 |
首次 HTTPS 请求与后续续签 |
HTTP-01 可达、443 站点正确、缓存保留与自动续签 |
DNS、ACME、TLS 实机验证 |
Not Run |
| AC-04 |
FR-05 |
桌面保存远端 HTTP/HTTPS 并检测 |
地址保存在设置;HTTP 提示且能检测,其他协议拒绝 |
Rust 单测、UI 构建;桌面实机待验证 |
部分验证 |
6. 发布与恢复
- 先完成本地构建和测试,备份现有二进制、确认公网 80/443 无占用及云安全组策略,再配置
VPN_TLS_DOMAIN 并切换新二进制。以 https://test-link.appx365.com/api/health 触发首次签发;确认 TLS 域名、证书到期和管理站点之后收敛 18080 公网权限。
- 若端口监听、HTTP-01 或首次握手失败,恢复原二进制/启动参数并重启旧
:18080 入口;data/acme 保留避免重复申请。不修改现有 VPN 网关或删除证书缓存。
- 私钥文件和用户数据不删除;证书吊销、DNS 变更及防火墙收敛分别决策。
7. 待决问题
| 问题 |
是否阻塞 |
推荐方案 |
| 云安全组 TCP 80/443 是否放行 |
阻塞线上 HTTP-01 |
先核实公网访问再签发 |
test-link.appx365.com 是否同时承载 OIDC 认证服务 |
不阻塞管理站点 |
初版仅反代管理站点;OIDC 独立域名或另行设计路径路由 |
| 证书到期告警 |
不阻塞本地实现 |
当前页面展示到期时间;后续可补主动告警 |