nginx -t 到底验证了什么
nginx -t 会解析配置文件、加载证书与私钥,并比对两者的模数是否相符——所以证书配错私钥确实会被挡下来,这点比很多人以为的严格。
但它的范围就到这里。它不知道你的证书涵盖哪些域名、不检查证书链是否完整、更不会模拟一次真实连接来看用户最后拿到什么。它验证的是「这份配置能不能加载」,不是「这份配置会产生什么结果」。
| 你看到的 | 实际验证了什么 | 没被涵盖的部分 |
|---|---|---|
| nginx -t 显示 successful | 语法正确,证书与私钥成对 | 证书链完整性、域名涵盖范围 |
| 证书文件已经是新的 | 磁盘上的文件确实更新了 | 未 reload 前仍供应内存中的旧证书 |
| server_name 配置正确 | 该域名的请求会命中这个块 | 不匹配的请求会落到 default server |
| 证书与中间证书都在同一个文件 | 内容齐全 | 顺序错误时 nginx 会取错那一张 |
下表把四种「看起来没问题」的状况与实际落差列出来。第二行是最常见的一种。
三个让配置与实际脱钩的机制
以下三种都是配置文件完全正确、但用户仍会出错的情况:
- 证书在内存里,不在文件里 Nginx 在启动或重新加载时把证书读进内存,之后就一直使用那一份。续签把文件换成新的并不会改变正在运行的进程——必须发送 reload 信号。这是「证书明明更新了却还是过期警告」最常见的原因,而且因为服务本身完全正常,很难联想到这一层。
-
TLS 握手发生在 Nginx 知道域名之前
官方文档讲得很直接:SSL 连接在浏览器发送 HTTP 请求之前就已建立,此时 Nginx 还不知道对方要的是哪个域名,因此只能先提供 default server 的证书。SNI 解决了这个问题——浏览器在握手阶段就带上域名——但若请求没有匹配到任何
server_name,仍会落到 default server,拿到那个块的证书。 -
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 接住其余的。没被涵盖的域名不会消失,只会静静拿到别人的证书。
排查时该先确认的三件事
遇到证书相关的反馈时,这三项能快速缩小范围:
- 确认是不是 reload 的问题 比对线上证书的 notBefore 与文件里的是否一致。不一致就是还没加载,这占了「证书更新了却没生效」的绝大多数。
-
确认用户连的域名有没有对应块
如果错误信息说证书属于另一个域名,先查
server_name是否涵盖,而不是怀疑证书本身。那张「别人的证书」通常就是 default server 的。 - 确认证书文件的排列顺序 如果 Nginx 直接以 key values mismatch 启动失败,在怀疑私钥之前先看顺序——服务器证书必须在最前面。这个错误信息很容易让人往错误的方向查。
小结
nginx -t 通过是必要条件,不是充分条件。它验证配置能否加载,但证书在内存里、TLS 握手早于域名判断、文件顺序决定哪张是服务器证书这三件事,都发生在它的检查范围之外。
这些机制本身没有问题,麻烦的是它们让「配置文件正确」产生了虚假的安全感。如果不想每次部署都逐项确认,我们的 SSL 证书自动化平台在签发后直接把完整证书链推送到各节点,减少手动编辑配置文件的环节。