真正生效的catch-all机制依赖listen...default_server而非server_name,需为HTTP和HTTPS端口分别配置带default_server的server块并用return 444静默断连。

直接配置一个带 default_server 标志的 server 块,就能捕获所有未被显式匹配的域名访问——这才是真正生效的 catch-all 机制,不依赖 server_name 的值,只靠 listen ... default_server 决定。
关键不是写什么 server_name,而是谁被标记为 default_server
Nginx 在收到请求时,先按 listen 的 IP:port 匹配 server 块,再用 Host 头去比对各块中的 server_name。一旦没有完全匹配的 server_name,就交给该端口上唯一标记了 default_server 的块处理。没标这个参数?那它就取配置文件里第一个同端口的 server 块——行为不可控,必须显式声明。
配置一个可靠的兜底 server(HTTP)
server {
listen 80 default_server;
server_name _; # 语义占位,实际不参与匹配
access_log /var/log/nginx/catchall.access.log main;
return 444; # 静默断连,不留响应痕迹
}-
return 444是最干净的选择:连接立即关闭,不发任何 HTTP 响应,避免暴露服务指纹或被扫描利用 - 日志单独存到
catchall.access.log,方便后续用awk '$1 !~ /^(yoursite\.com|www\.yoursite\.com)$/ {print $1}'提取非法 Host - 不要在这里写
root或location,避免无意中暴露默认页面或目录结构
HTTPS 同样需要独立配置 default_server
HTTP 和 HTTPS 是不同端口(80 vs 443),必须分别设 default_server:
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/nginx/ssl/fallback.crt; # 必须存在,哪怕自签
ssl_certificate_key /etc/nginx/ssl/fallback.key;
return 444;
}⚠️ 注意:
- SSL 证书路径必须真实可读,否则 Nginx 启动失败
- 如果用的是较新版本(≥1.19.4),更推荐全局开启
ssl_reject_handshake on;,在 TLS 握手阶段就拒绝非法 SNI,连证书都不发
确保它真生效:验证方法
- 用 curl 模拟非法 Host:
curl -H "Host: evil.com" http://your-server-ip/→ 应返回空响应(curl: (52) Empty reply from server) - 检查日志是否写入
catchall.access.log - 运行
nginx -T | grep -A5 "listen 80.*default_server"确认配置被正确加载
不要做的几件事
- 不要用
server_name *或server_name ""代替default_server—— 它们不触发兜底逻辑 - 不要把 catch-all 块放在业务 server 之后又不加
default_server—— 它可能根本不会被选中 - 不要在 catch-all 里返回 404 或 301 —— 这等于告诉攻击者“这里有个 Web 服务”,反而增加风险
本质上,catch-all 就是一道守门人,它的任务不是服务,而是过滤。配对、重启、验证,三步做完,非法域名和 IP 直连就自然被挡在外面。


















