Nginx的server_name仅用于匹配Host头并路由请求,不具访问控制功能;真正限制未授权访问需显式配置default_server块返回444或403,或在业务块内用if校验$host。

直接在 server 块中用 server_name 指令本身并不能“限制”访问,它只是告诉 Nginx 这个块该响应哪些域名的请求。真正起限制作用的是:**没匹配上的请求,Nginx 会交给谁处理?** 所以关键在于控制“未命中域名”的流向。
明确指定 server_name 并配默认拦截块
这是最稳妥、推荐的主流做法。原理是显式定义一个“兜底 server”,专门捕获所有非授权域名(包括直接 IP 访问)的请求,并统一拒绝:
- 添加一个带
default_server标识的 server 块,监听相同端口(如 80 或 443),server_name _(下划线是 Nginx 的通配占位符) - 在这个块里直接返回
403或更彻底的444(Nginx 特有,静默断连) - 你的业务 server 块只写真实允许的域名,不加
default_server
示例配置:
server {listen 80 default_server;
server_name _;
return 444;
}
server {
listen 80;
server_name example.com www.example.com;
root /var/www/html;
index index.html;
}
在业务 server 块内用 if 判断 host
适合单站点、不想额外加 server 块的场景。它在请求进入后,再检查 Host 头是否合规:
- 使用
if ($host !~ ^(example\.com|www\.example\.com)$)正则匹配(注意点号要转义) - 或用严格等值判断
if ($host != 'example.com' && $host != 'www.example.com') - 匹配失败就
return 403
⚠️ 注意:if 在 location 外使用有局限性,且 Nginx 官方不建议在高并发场景过度依赖 if;但用于 host 校验是常见且安全的做法。
为什么不能只靠 server_name?
server_name 是匹配机制,不是访问控制开关。如果你只写:
而没设 default_server,Nginx 会把第一个加载的 server 块当作默认响应器。别人用任意域名甚至 IP 直连,只要没别的 server 匹配上,就会落到你这个块里——等于完全开放。
补充:防止恶意解析的关键细节
- 确保所有监听端口(80/443)都配了
default_server块,避免遗漏 - HTTPS 配置同样需要独立的
default_server块(listen 443 ssl default_server) - 若用泛域名(如
*.example.com),需确认是否真需支持所有子域;否则建议精确列出 - 测试时可用
curl -H "Host: evil.com" http://your_ip模拟恶意请求,验证是否被拦截


















