Nginx配置疑问:为何带test.com主机头的HTTP请求匹配了HTTPS默认服务器块
Nginx配置疑问:为何带test.com主机头的HTTP请求匹配了HTTPS默认服务器块
这个问题的核心在于Nginx对请求的处理顺序:协议层的校验优先级远高于server_name的匹配逻辑,咱们一步步拆解清楚:
先看你的两个server块的监听差异:
- 第一个块是
listen 8200;:表示监听8200端口,处理纯HTTP请求 - 第二个块是
listen 8200 ssl default_server;:这里的ssl标记是关键——它告诉Nginx,这个8200端口的监听套接字要强制启用SSL/TLS协议,只能处理HTTPS请求;同时default_server意味着如果请求匹配不到其他server块,就 fallback 到这个块
- 第一个块是
当你执行
curl -H "Host: test.com" http://127.0.0.1:8200时,发送的是纯HTTP请求——没有SSL握手过程,直接就发了HTTP的请求行和头信息。这时候Nginx的处理流程是:- 首先检查8200端口的监听套接字:因为第二个server块的
listen 8200 ssl已经把这个端口的套接字设置为SSL模式,Nginx会先尝试和客户端完成SSL握手 - 但你的请求是纯HTTP,根本没有SSL握手的步骤,Nginx立刻识别出这是非法请求,直接返回
400 Bad Request: plain HTTP request was sent to HTTPS port - 这个过程发生在Nginx解析HTTP请求头(包括
Host字段)之前,所以第一个server块的server_name test.com根本没机会参与匹配!
- 首先检查8200端口的监听套接字:因为第二个server块的
验证这个逻辑的小方法:
- 把第一个server块的监听端口改成8201,比如:
server { listen 8201; server_name test.com; location / { return 200 'Block1'; } } - 再执行
curl -H "Host: test.com" http://127.0.0.1:8201,就会正常返回Block1,说明server_name的匹配逻辑本身是正常的,问题出在端口的SSL标记冲突上
- 把第一个server块的监听端口改成8201,比如:
更合理的配置建议:
- 不要在同一个端口上混合配置HTTP和HTTPS的server块,应该分开端口(比如80端口跑HTTP,443跑HTTPS),这也是行业通用的做法
- 如果特殊场景下必须用同一个端口,需要借助SNI等高级配置,但这种需求非常少见,不推荐
备注:内容来源于stack exchange,提问作者Parzival
相关产品推荐
相关产品推荐

