核心是配置独立default_server块拦截未匹配请求:http用listen 80 default_server+server_name _+return 444;https用listen 443 ssl default_server+ssl_reject_handshake on或配证书后return 403,确保ip直连在协议层被阻断。

要让 Nginx 反向代理网关只响应域名访问、拒绝直接用 IP 地址访问,核心思路是:**用一个独立的 default_server 拦截所有未匹配 server_name 的请求,并返回明确拒绝响应**。这不是靠隐藏或重定向,而是主动识别并阻断。
配置一个专用的默认 server 拦截 IP 访问
这是最可靠、最符合 Nginx 匹配机制的做法。Nginx 会把没有匹配到任何 server_name 的请求(比如直接输 http://192.168.1.100)交给标记为 default_server 的那个 server 块处理。
- 在 nginx.conf 或站点配置文件中,新增一个监听 80(和 443)端口的 server 块,加上 default_server 标识
- 这个块不设有效的 server_name,或仅设通配符 _
- 里面不写 proxy_pass,而是直接 return 403 或 444(静默关闭连接)
示例:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 403;
}
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /path/to/empty.crt;
ssl_certificate_key /path/to/empty.key;
return 403;
}
注意:这个块必须放在所有其他 server 块之前或之后都可,但不能嵌套在别的块里;且确保它确实是该端口的 default_server(即 listen 指令带 default_server 参数)。
确保业务 server 块明确声明 server_name
你的实际服务配置必须显式写出合法的域名,不能依赖通配或留空。
- 错误写法:
server_name ;或server_name "";—— 这会让它退化为默认行为,可能被 IP 请求命中 - 正确写法:
server_name example.com www.example.com;或多个域名用空格分隔 - 如果想支持任意子域名,可用通配符:
server_name *.example.com;(注意通配符只能在最左端)
避免用 if 判断 $host 的方式
像 if ($host = "192.168.1.100") { return 403; } 这类写法看似直观,但存在隐患:
- if 在 location 中属于“非标准上下文”,Nginx 官方不推荐用于访问控制
- $host 来自请求头,可能被客户端伪造,不可信
- 一旦和其他指令(如 proxy_pass)混用,容易触发意外匹配或优先级问题
- 无法拦截 HTTPS 握手阶段的 SNI 不匹配请求(而 default_server 可以)
补充:对 HTTPS 的额外考虑
HTTP 可靠靠 default_server 拦截,但 HTTPS 需要注意:
- 浏览器在发起 HTTPS 请求前会通过 SNI(Server Name Indication)告知目标域名
- 如果用户直接用 IP 访问 HTTPS,SNI 字段为空或为 IP,Nginx 会匹配到你定义的
default_server的 SSL 块 - 所以必须为 default_server 的 443 块提供有效的证书(哪怕只是自签名),否则 TLS 握手失败,用户看到的是浏览器证书错误,而非 403
- 若不想管证书,可改用
return 444;(Nginx 特有状态码,直接断连,不发任何响应)











