为网站配置域名后,直接访问服务器 IP 有时仍会显示网站内容。这通常是因为请求没有匹配任何 server_name,最终落到了该监听地址的默认虚拟主机上。
可以单独设置默认虚拟主机接住这类请求:HTTP 关闭连接,HTTPS 则在未匹配域名的 TLS 握手阶段拒绝。下面的配置适用于支持 ssl_reject_handshake 的 Nginx,最低版本为 1.19.4。
一、默认虚拟主机由 listen 决定
server_name _; 只是一个通常不会被正常域名匹配的名字,并不自动代表“所有域名”。负责兜底的是 listen 上的 default_server。
同一监听地址和端口只能设置一个默认虚拟主机。添加前先检查现有配置;Debian/Ubuntu 的默认站点文件、面板生成的站点配置都可能已经设置了它。相关选择顺序见 Nginx 请求处理文档。
二、添加 HTTP 和 HTTPS 兜底配置
把下面两个 server 块放在 Nginx 的 http 上下文中,例如已由 nginx.conf 引入的站点配置文件:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
ssl_reject_handshake on;
return 444;
}
如果系统没有启用 IPv6,去掉两个 [::] 监听。若实际网站只监听某个指定 IP,需要为对应的地址、端口设置默认虚拟主机,而不是只复制通配地址配置。
HTTP 部分应使用 return 444,不是 return 0。444 是 Nginx 的特殊处理:关闭连接而不向客户端发送 HTTP 响应头。浏览器或 curl 因此可能显示空响应,而不是一个内容为“444”的网页。return 指令说明对此有明确规定。
HTTPS 部分使用 ssl_reject_handshake on,无需给这个拒绝握手的默认块随意配置一张证书。TLS 握手发生在 HTTP 请求之前,单纯的 return 444 无法替代握手拒绝。ssl_reject_handshake 文档给出了同样的默认主机用法。
正常域名站点继续保留自己的 server_name、证书、静态目录或反向代理配置。不要把 ssl_reject_handshake on 加到需要正常访问的域名站点里。
三、检查并重新加载
sudo nginx -t
确认检查成功后,再重新加载:
sudo systemctl reload nginx
如果报 duplicate default server,先处理同一监听地址上的重复配置;如果报不认识 ssl_reject_handshake,检查实际运行的 Nginx 版本,而不是继续添加证书来掩盖问题。
四、同时验证拒绝与正常访问
以下 203.0.113.10 和 www.example.com 均为占位值,替换成自己的服务器 IP 与正常站点域名。
直接请求 IP:
curl -v http://203.0.113.10/
curl -vk https://203.0.113.10/
预期前者连接关闭、不返回网站页面,后者 TLS 握手失败。第二条命令的 -k 仅用于排查证书校验因素,它不会让被服务端拒绝的握手成功。
再验证正常域名。使用 --resolve 可以绕过 DNS 解析,仍以正确域名发送 Host 和 TLS SNI:
curl -I --resolve www.example.com:80:203.0.113.10 http://www.example.com/
curl -I --resolve www.example.com:443:203.0.113.10 https://www.example.com/
此时应进入正常网站,得到站点原本的响应或跳转。只测“IP 打不开”不够,还要确认正常域名没有一起被拒绝。
五、这项配置的边界
它处理的是未匹配的 Host/SNI,不是按来源 IP 做访问控制。知道正确域名的客户端仍能连接服务器 IP,并携带正确的 Host/SNI 访问网站,前面的 --resolve 测试正好展示了这一点。
如果目标是让源站只接受 CDN 或特定客户端的连接,还需要单独设置网络访问策略。这里的默认虚拟主机只负责避免把普通 IP 访问和未匹配域名请求交给真实站点。
评论区