跳到主要内容

解决Nginx多SSL配置中未匹配域名的默认回退问题

· 阅读需 2 分钟

问题现象

我给 nginx 配置了多个server,分别设置了 ssl 代理,但是当其中一个服务未启动是,会访问到第一个 server 的内容。

server {
listen 443 ssl;
server_name a.domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://xxxx:10010;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 443 ssl;
server_name b.domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://xxxx:10086;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

当 10086 端口的服务未启动时,访问 https://b.domain.com 时,会出现 10010端口的服务的内容。 也就是 nginx 只会访问第一个 server 的内容。经过一番查找,发现是因为没有设置 default_server

解决方案

添加一个下面的 server 配置

server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
return 444; # 立即关闭连接
}

问题剖析

Nginx 请求匹配机制

  1. 端口监听优先级:Nginx优先匹配 listen指令相同的配置
  2. 域名精确匹配:在相同监听端口中,server_name最精确匹配的配置生效
  3. 默认回退机制:当没有匹配的server_name 时,自动选择:
    • 第一个定义的 server 块(未显式声明 default_server 时)
    • 标记为default_server的配置块

问题根源

当后端服务不可达时,Nginx 的请求处理流程:

  1. 客户端请求 b.domain.com
  2. Nginx正确匹配到 b.domain.com 的 server 块
  3. 尝试代理到http://xxxx:10086时发现连接失败
  4. 错误配置导致匹配降级,回退到默认 server 块(第一个定义的 a.domain.com