server_name 匹配自签证书域名时为何失败
在 linux nginx 中,server_name 处理企业内网自签证书的核心在于:nginx 必须根据请求的 host 头精确匹配到包含该域名的 server 块,且该块加载的 ssl 证书必须包含对应的 san(subject alternative name)或 cn。如果配置了多个虚拟主机,nginx 会优先使用与 server_name 完全匹配的证书;若未找到匹配项,则返回默认服务器(default_server)的证书。对于自签证书,由于没有受信任的 ca 签名,浏览器会报错,但 nginx 层面的握手能否成功取决于域名是否被正确包含在证书的扩展字段中。

server {
listen 443 ssl;
server_name internal.example.com;
ssl_certificate /etc/nginx/ssl/internal.crt;
ssl_certificate_key /etc/nginx/ssl/internal.key;
location / {
proxy_pass http://backend;
}
}
上述配置展示了最基础的单域名自签证书部署。关键在于 internal.example.com 必须出现在 internal.crt 的 SAN 列表中。如果客户端请求的是 www.internal.example.com,而证书中只有 internal.example.com,且没有其他 server 块匹配,Nginx 可能会回退到默认站点或拒绝连接,具体取决于 Nginx 版本和配置。
多域名自签证书如何统一在一个 server_name 下处理
当企业内网需要为多个子域名提供自签证书服务时,最佳实践是使用通配符证书或在单个证书中包含所有 SAN。Nginx 的 server_name 支持通配符,如 *.example.com,但这要求证书本身也必须是通配符证书或包含所有具体域名。如果证书只包含特定域名,而 server_name 使用了通配符,Nginx 可能无法正确关联证书,导致 TLS 握手失败或浏览器警告。

# 生成包含多个 SAN 的自签证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/multi.key \
-out /etc/nginx/ssl/multi.crt \
-subj "/CN=*.example.com" \
-addext "subjectAltName=DNS:*.example.com,DNS:example.com,DNS:mail.example.com"
server {
listen 443 ssl;
server_name *.example.com example.com mail.example.com;
ssl_certificate /etc/nginx/ssl/multi.crt;
ssl_certificate_key /etc/nginx/ssl/multi.key;
location / {
proxy_pass http://backend;
}
}
此代码块演示了如何创建一个包含多个 SAN 的自签证书,并在 Nginx 中配置 server_name 以匹配这些域名。注意 -addext 参数用于指定 SAN,确保证书能被正确识别。Nginx 会根据请求的 Host 头选择最匹配的 server 块,并使用其配置的证书进行 TLS 握手。
自签证书缺少 SAN 时 server_name 如何处理
如果自签证书仅设置了 CN 而未设置 SAN,现代浏览器和 Nginx 的行为会有所不同。Nginx 本身在 TLS 握手阶段主要检查证书的有效性(包括域名匹配),但如果证书没有 SAN,某些严格的客户端可能会拒绝连接。在这种情况下,server_name 虽然能匹配到正确的 server 块,但 TLS 握手可能因证书格式问题而失败。解决方法是重新生成证书,确保包含 SAN。
验证步骤如下:首先检查证书内容,确认是否有 SAN。如果没有,使用 OpenSSL 重新生成证书。其次,测试 Nginx 配置是否正确加载证书。最后,使用 curl 或浏览器测试连接,观察错误信息。如果错误提示“certificate has no SAN”,则需修改证书生成命令,添加 -addext 参数。











