Nginx 未匹配 Host 请求的兜底机制依赖 listen 指令的 default_server 标志,而非 server_name _;同一端口仅允许一个 default_server,它会处理空 Host、IP 访问及非法域名请求,并需为 HTTPS 配置有效证书。

当 Nginx 收到一个请求,但它的 Host 请求头无法匹配任何 server_name 时,它不会自动跳到某个“空名字”的 server 块——而是取决于有没有配置 default_server。
兜底的关键是 default_server,不是 server_name _
很多人误以为写 server_name _; 就能兜底,其实它只是个惯例占位符,不参与实际匹配。真正起作用的是 listen 指令里的 default_server 标志:
-
listen 80 default_server;表示这个 server 块是 80 端口的默认入口 - 所有未被其他
server_name显式匹配的请求(包括 IP 直接访问、空 Host、非法域名)都会落到它这里 - 同一个端口只能有一个
default_server,否则nginx -t会报错 - 即使里面写
server_name "";或干脆不写server_name,只要加了default_server,它就生效
典型兜底配置写法
推荐在所有正式站点配置之前,单独定义一个兜底 server 块:
server {
listen 80 default_server;
listen 443 ssl default_server;
ssl_certificate /path/to/empty.crt;
ssl_certificate_key /path/to/empty.key;
<pre class="brush:php;toolbar:false;"># 可选:显式拒绝非法 Host 头
if ($host !~ ^(example.com|www.example.com)$) {
return 444;
}
# 或统一返回 404
return 404;
# 或重定向到主站(需确保主站已配好)
# return 301 https://example.com$request_uri;}
注意 HTTPS 的兜底块必须提供有效的证书(哪怕只是自签),否则连接会直接失败;如果不想支持 HTTPS 访问 IP,可只配 listen 80 default_server 并返回 444。
常见错误排查点
如果兜底没生效,检查以下几项:
- 是否已有其他 server 块抢先用了
default_server?删掉重复项 - 兜底块是否放在
include文件的最前面?Nginx 按配置顺序加载,但default_server优先级高于顺序 - 是否漏写了
default_server,只写了server_name _;?后者完全无效 - 用
curl -H "Host:" http://your-ip或curl http://your-ip测试空 Host 和 IP 访问,确认日志进的是哪个 server
为什么不能靠 server_name _ 来兜底
Nginx 匹配逻辑是“找第一个能匹配的”,不是“找最符合的”。server_name _; 不匹配任何真实 Host,但它本身不拦截请求——如果前面有个 server { listen 80; server_name example.com; },那所有 IP 访问都会进这个块,根本轮不到 _。只有加上 default_server,才能强制它成为最后防线。











