Nginx 中 server_name 无法匹配空主机头,真正起作用的是 default_server 标志;应配置带 default_server 的 server 块,用 if ($host = "") 判断并 return 444 拦截。

在 Nginx 中,server_name 本身**不能直接匹配空主机头(即请求中没有 Host 头)**,因为 server_name 的匹配机制只作用于 HTTP/1.1 请求中明确携带的 Host 请求头字段。当客户端发送的请求不带 Host 头(常见于 HTTP/1.0 请求、恶意扫描、或某些原始 TCP 工具如 curl -H "Host:" 或直接 telnet 发送),Nginx 不会用 server_name 去比对,而是交由「默认 server」处理。
什么是空主机头流量?
空主机头指请求中 Host: 后为空(Host:)或完全缺失 Host 头。这类请求不符合 HTTP/1.1 规范,但 Nginx 仍会接收并尝试路由。它不会触发任何 server_name 匹配(包括 ""、"_" 或正则 ~^$),因为匹配逻辑根本不执行。
如何捕获并处理空主机头请求?
正确做法是:**显式定义一个默认 server,并在其中用 if + $host 或 $http_host 判断是否为空**:
-
$host是 Nginx 内部变量,值为解析后的 Host(优先取Host头,无则为空字符串) -
$http_host是原始请求头内容(可能含端口,缺失时为未定义) - 推荐用
$host = ""判断——更稳定、语义清晰
示例配置:
server {
listen 80 default_server;
server_name _; # 占位,实际不参与匹配
<pre class="brush:php;toolbar:false;"># 拦截空 host 请求
if ($host = "") {
return 444; # 或 400 / 444(关闭连接)/ 重定向等
}
# 其他 location...}
为什么不能用 server_name "" 或 server_name "_"?
server_name "" 在语法上合法,但 Nginx 会将其视作「匹配任意非空 Host」(行为类似通配符),并非匹配空值;而 server_name "_" 只是常用占位符,表示“无意义名称”,它不会匹配空 Host,仅用于让该 server 成为 default_server 的候选之一。真正起作用的是 default_server 标志,而非 server_name 的值。
生产环境建议
- 始终设置
default_server,避免未匹配请求落到意外 server 块 - 对空 Host 请求返回
444(Nginx 特有,直接断连)或400(Bad Request),防止被滥用于探测或绕过规则 - 避免在
if中使用复杂逻辑;此处判断$host = ""是安全且高效的操作 - 若需区分「Host 缺失」和「Host 为空字符串」,可用
$http_host = ""配合$host = ""组合判断(极少需要)











