Nginx默认允许IP访问是因为未匹配server_name时会回退到首个或default_server块;解决方法是在vhost目录下新建00-block-ip.conf,配置listen 80/443 default_server、server_name ""并return 444,同时补全IPv6监听和dummy证书。

为什么 Nginx 会允许 IP 直接访问?
默认 phpEnv 的 Nginx 配置里,server 块没设 server_name 或只写了泛域名,导致 Nginx 把该配置当作“默认虚拟主机”来响应所有未匹配的请求——包括直接用 http://123.45.67.89 访问。这不是漏洞,是 Nginx 的 fallback 行为。
如何让 Nginx 拒绝 IP 访问并只认指定域名?
核心思路:定义一个「空 server_name」的兜底 server,把它放在所有其他 server 块之前,并返回 444(Nginx 特有关闭连接状态码,比 403/404 更干净)。
在 phpEnv 的 Nginx 配置目录(通常是 /phpenv/nginx/conf/vhost/)下,新建一个文件如 00-block-ip.conf,内容如下:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name "";
return 444;
}
注意几点:
立即学习“PHP免费学习笔记(深入)”;
-
default_server必须加在listen后,否则不生效 -
server_name ""是关键,不能写成server_name _;或留空不写 - 文件名以
00-开头,确保它被 Nginx 最先加载(phpEnv 按字母序读取 vhost 文件) - 如果开了 HTTPS,同样要加一个
listen 443 ssl default_server的对应块,并配好 dummy 证书(或复用已有证书),否则 HTTPS 下 IP 仍可通
phpEnv 中修改后不生效?检查这几个地方
常见失效原因不是配置错,而是没触发重载或路径不对:
- 确认你改的是
/phpenv/nginx/conf/vhost/下的文件,不是/phpenv/nginx/conf/nginx.conf主配置里的http块 - 执行
/phpenv/nginx/sbin/nginx -t验证语法,失败会提示具体哪行错 - 验证通过后必须运行
/phpenv/nginx/sbin/nginx -s reload,restart不可靠 - 浏览器可能缓存了 301 跳转或 HSTS,换隐身窗口或用
curl -I http://你的IP测试响应头,看是否返回HTTP/1.1 444
HTTPS 下域名限定更麻烦?
因为 TLS 握手发生在 HTTP 请求前,Nginx 必须先选一个 server 块才能读 Host 头。所以仅靠 server_name 不足以拦截 HTTPS 的 IP 访问——得靠 SNI 匹配。
解决办法:
- 在
00-block-ip.conf里补上 HTTPS 版本,用最小化证书(自签也行,只要格式对):
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name "";
ssl_certificate /phpenv/nginx/conf/ssl/dummy.crt;
ssl_certificate_key /phpenv/nginx/conf/ssl/dummy.key;
return 444;
}
生成 dummy 证书命令(只需一次):
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -subj "/CN=localhost" \ -keyout /phpenv/nginx/conf/ssl/dummy.key \ -out /phpenv/nginx/conf/ssl/dummy.crt
没有这一步,Nginx 启动会报 no "ssl_certificate" is defined 错误。
实际部署中,最容易被忽略的是 IPv6 的 [::]:80 和 [::]:443 监听——不加的话,IPv6 地址仍可直连。



















