← 返回文章归档

443 开着却没有 HTTPS:一次博客部署排障记录

记录博客从 HTTP 切换 HTTPS 的实际修复:识别明文 443、按协议保留原站点、补齐上传限制,以及验证证书续期和数据一致性。

首页能打开,部署就算完成了吗

这次检查博客时,HTTP 首页、健康检查和文章接口都正常,容器也是 healthy。但切换到 HTTPS 就握手失败,说明“服务在运行”和“用户访问链路正确”是两件事。

继续看宿主机 Nginx 配置,才发现 443 上已有另一个学习站点,而且使用的是明文 HTTP。监听了通常属于 HTTPS 的端口,并不会自动让流量加密;TLS 仍需要对应的监听配置和证书。

修复还涉及两个较小的问题:默认站点名称 _ 重复产生警告,以及宿主机请求体上限低于后台支持的图片大小。

先把三段链路分开检查

我把请求路径拆成三个位置:容器应用、宿主机代理、公网入口。

浏览器
  -> 公网 80 / 443
  -> 宿主机 Nginx
  -> 127.0.0.1:8080
  -> 博客容器

容器应用的 /healthz 返回 ok,只能说明这一路局部正常。接下来还要检查域名解析、代理目标、HTTP 状态、TLS 握手,以及页面里的 canonical、RSS 和站点地图是否使用正确地址。

这样排查时,证据会比较清楚:本机上游正常而 HTTPS 握手失败,应先看公网协议入口,而不是反复重建应用。

原来的明文 443 入口还需要继续使用

直接把原监听改成 TLS,会改变面试学习网站既有的访问方式。当前采用 Nginx stream 预读协议,把 TLS 流量与明文 HTTP 分到两个回环后端,方法可以对照 Nginx ssl_preread 官方文档。

最终拓扑是:

公网流量本机目标用途
80博客 HTTP serverACME 验证;其他请求跳转 HTTPS
443,TLS127.0.0.1:8443博客 HTTPS
443,明文 HTTP127.0.0.1:8444原面试学习网站

8443、8444 和容器 8080 都只监听本机。stream 转发还通过 PROXY protocol 传递原客户端地址;后端配套启用并只信任本机来源,避免日志和代理头全部变成回环地址。

这是当前服务器为了兼容已有入口作出的选择。普通单站点服务器如果没有这项约束,不必为了配置 HTTPS 就引入相同拓扑。

证书和应用地址要一起调整

证书通过 HTTP webroot 验证签发,80 端口单独保留 /.well-known/acme-challenge/,其他路径跳转到主域名。www 也有证书,并统一跳转到 https://yellowtt.cn。

应用的构建地址也同步改成 HTTPS。这个博客会用它生成 canonical、RSS、站点地图,并检查后台写请求的来源;只在代理外面加 TLS,而应用还认为自己属于另一个地址,会留下链接和后台操作问题。

新镜像先完成类型检查、生产构建和独立容器里的后台集成测试,再替换线上容器。原镜像、Nginx 配置、环境文件与文章数据都提前留有备份。

413 应当在哪一层修

应用允许单张图片最多 5 MiB,原来的宿主机 Nginx 却会更早拒绝大请求。请求连应用都到不了,修改上传函数没有作用。

博客 server 现在配置 client_max_body_size 6m,让应用继续执行自己的 5 MiB 校验。验证时实际发送了 1 MiB 以上和 5 MiB 的未登录请求,得到应用返回的 401,说明请求通过了 Nginx,没有创建上传文件。

只手写一个很大的 Content-Length 却不发送请求体,并不能完成这项验证;代理允许以后会等待剩余正文,等待超时不等于应用停止工作。

最后检查用户真的会走到的地方

这次上线核对了 23 项公开端点,以及 31 项浏览器页面和跳转;桌面、手机、搜索和主题保存都通过。后台实际登录与退出也正常,会话 Cookie 带 Secure 和 HttpOnly。

原学习网站首页与博客文章数据的 SHA-256 在切换前后保持一致。Nginx 配置检查不再出现名称冲突,证书模拟续期与续期后的重新加载也成功,自动续期任务已启用。

这次最值得保留的排障顺序是:先确定失败发生在哪段链路,再修改那一层;切换之前准备恢复材料,切换之后用真实入口验证。容器 healthy 是其中一项证据,不能替代整条访问路径的检查。

✳

感谢阅读,下一篇再见。

回到文章开头 ↑