nginx -t 到底验证了什么

nginx -t 会解析配置文件、加载证书与私钥,并比对两者的模数是否相符——所以证书配错私钥确实会被挡下来,这点比很多人以为的严格。

但它的范围就到这里。它不知道你的证书涵盖哪些域名、不检查证书链是否完整、更不会模拟一次真实连接来看用户最后拿到什么。它验证的是「这份配置能不能加载」,不是「这份配置会产生什么结果」。

你看到的 实际验证了什么 没被涵盖的部分
nginx -t 显示 successful 语法正确,证书与私钥成对 证书链完整性、域名涵盖范围
证书文件已经是新的 磁盘上的文件确实更新了 未 reload 前仍供应内存中的旧证书
server_name 配置正确 该域名的请求会命中这个块 不匹配的请求会落到 default server
证书与中间证书都在同一个文件 内容齐全 顺序错误时 nginx 会取错那一张
四种配置看似正确、但用户端仍可能出错的情况。

下表把四种「看起来没问题」的状况与实际落差列出来。第二行是最常见的一种。

三个让配置与实际脱钩的机制

以下三种都是配置文件完全正确、但用户仍会出错的情况:

  1. 证书在内存里,不在文件里 Nginx 在启动或重新加载时把证书读进内存,之后就一直使用那一份。续签把文件换成新的并不会改变正在运行的进程——必须发送 reload 信号。这是「证书明明更新了却还是过期警告」最常见的原因,而且因为服务本身完全正常,很难联想到这一层。
  2. TLS 握手发生在 Nginx 知道域名之前 官方文档讲得很直接:SSL 连接在浏览器发送 HTTP 请求之前就已建立,此时 Nginx 还不知道对方要的是哪个域名,因此只能先提供 default server 的证书。SNI 解决了这个问题——浏览器在握手阶段就带上域名——但若请求没有匹配到任何 server_name,仍会落到 default server,拿到那个块的证书。
  3. Nginx 只把文件里的第一张证书当作服务器证书 ssl_certificate 指向的文件可以包含多张证书,但服务器证书必须排在最前面,后面才是中间证书。官方文档明确要求这个顺序。如果拼接时顺序颠倒,Nginx 会拿中间证书去配对你的私钥,然后以 key values mismatch 启动失败——错误信息指向私钥,但真正的问题在顺序。

default server 为什么会咬到你

Nginx 在同一个监听地址上,若没有任何 server 块标记 default_server,第一个块就自动成为默认。所以配置文件里块的排列顺序,会直接决定「域名不匹配时用户看到谁的证书」。

这造成的症状很容易误导:某个域名明明配置正确,用户却收到「证书属于别的域名」的警告。典型情境是新增了一个域名但 DNS 已经指过来、而 server_name 还没写对,或是有人直接用 IP 地址连接——这两种都会落到 default server。

另外要知道 SNI 并非万无一失。TLS 1.3 要求实现 SNI,现代浏览器都会发送,但某些旧客户端、以及直接以 IP 连接的请求不会带。对这些情况,default server 的证书就是他们唯一会拿到的东西。

确认用户实际拿到什么

所有检查的原则都一样:不要看配置文件,要看服务器实际发送什么。openssl s_client -connect 域名:443 -servername 域名 会建立一次真实握手并打印证书,其中 -servername 就是发送 SNI,这一项不能省——省掉它等于在测试「没有 SNI 的客户端会拿到什么」,结果会是 default server 的证书。

要验证 reload 是否确实生效,比对证书的有效期起始时间(notBefore)最直接。如果线上供应的证书起始时间仍是旧的那一张,代表进程还没重新加载。这比检查文件修改时间可靠,因为文件早就更新了。

三个层次的配置检查

依可靠度由低到高:

一、nginx -t 只当作第一道

它能挡下语法错误与证书私钥不配对,值得每次改完都跑。但通过不代表配置正确,只代表配置能被加载。把它当作必要条件而非充分条件。另外值得顺手清掉的是已经失效的配置,例如 OCSP 装订——它在多数证书上已经不再有作用。

二、改完证书一定要 reload,并确认生效

nginx -s reload 或对应的服务命令。重点是之后要实际连一次确认——reload 可能因为配置错误而失败,而旧的进程会继续正常服务,从外部看不出任何异状。

三、明确指定 default_server 与涵盖范围

列出所有会连到这台机器的域名,确认每一个都有对应的 server_name,并指定一个专门的 default_server 接住其余的。没被涵盖的域名不会消失,只会静静拿到别人的证书。

排查时该先确认的三件事

遇到证书相关的反馈时,这三项能快速缩小范围:

  1. 确认是不是 reload 的问题 比对线上证书的 notBefore 与文件里的是否一致。不一致就是还没加载,这占了「证书更新了却没生效」的绝大多数。
  2. 确认用户连的域名有没有对应块 如果错误信息说证书属于另一个域名,先查 server_name 是否涵盖,而不是怀疑证书本身。那张「别人的证书」通常就是 default server 的。
  3. 确认证书文件的排列顺序 如果 Nginx 直接以 key values mismatch 启动失败,在怀疑私钥之前先看顺序——服务器证书必须在最前面。这个错误信息很容易让人往错误的方向查。

小结

nginx -t 通过是必要条件,不是充分条件。它验证配置能否加载,但证书在内存里、TLS 握手早于域名判断、文件顺序决定哪张是服务器证书这三件事,都发生在它的检查范围之外。

这些机制本身没有问题,麻烦的是它们让「配置文件正确」产生了虚假的安全感。如果不想每次部署都逐项确认,我们的 SSL 证书自动化平台在签发后直接把完整证书链推送到各节点,减少手动编辑配置文件的环节。

参考资料