ssl_reject_handshake可从TLS握手层彻底拒绝IP直连,不发证书、不响应ServerHello、不进入HTTP流程;需Nginx≥1.19.4且启用stream_ssl_preread模块,在default_server的443 server块中仅配置ssl_reject_handshake on,严禁证书相关指令。

直接用 IP 地址访问 HTTPS 服务时,Nginx 默认会返回默认站点的证书,导致域名与源站 IP 关联暴露——ssl_reject_handshake 就是为从 TLS 握手层彻底切断这一泄露链而设的:它不发证书、不响应 ServerHello、不进入 HTTP 流程,连接在握手阶段就被内核级拒绝。
确认前提条件是否满足
该指令仅在 Nginx ≥ 1.19.4 且启用 stream_ssl_preread 模块时可用。多数主流环境(如宝塔、Oneinstack、Ubuntu/Debian 官方包)已默认支持。可通过以下命令验证:
-
nginx -v查看版本是否 ≥ 1.19.4 -
nginx -V 2>&1 | grep -o with-stream_ssl_preread_module输出非空即表示模块已编译启用
配置专用的 default_server 拦截块
不能复用已有网站的 server 块,必须新建一个仅用于兜底的 443 监听块,且不含任何证书配置:
- 监听声明中必须含
default_server,确保它匹配所有未被server_name显式覆盖的请求(包括 IP 直连和非法 SNI) - 块内只写
listen 443 ssl default_server;和ssl_reject_handshake on; - 严禁出现
ssl_certificate、ssl_certificate_key或其他 SSL 参数,否则 Nginx 启动失败
示例配置:
<pre>server {listen 443 ssl default_server;
ssl_reject_handshake on;
}
</pre>
验证拦截是否生效
用真实工具测试,观察是否在 TLS 层就中断:
-
curl -vI https://你的服务器IP—— 应卡在 TLS 握手,无证书输出,无 HTTP 状态码 - 浏览器访问该地址,显示
ERR_SSL_UNRECOGNIZED_NAME_ALERT(Chrome)或SSL_ERROR_UNRECOGNIZED_NAME_ALERT(Firefox) -
openssl s_client -connect 你的IP:443 -servername example.com—— 应失败;但换为合法域名(如已配置的example.com)应能成功握手
搭配其他防护避免绕过
单靠 ssl_reject_handshake 不足以全面防泄露,需组合加固:
- 对 HTTP 的 80 端口也设置
listen 80 default_server; return 444;,防止 HTTP 层暴露 - 生产证书中避免泛域名(如
*.example.com),只列出真实使用的精确域名 - 申请 Let’s Encrypt 时不用
--standalone模式,改用--webroot或 DNS 验证,避免临时开放源站端口


















