我在 Debian Bookworm 上运行默认的 nginx 包。通常我只使用 HTTPS 连接该服务,一切正常。HTTP 端口 80 的默认重定向到 HTTPS 协议。
server {
listen 80 default_server;
listen [::]:80 default_server;
server_tokens off;
return 301 https://$host$request_uri;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log error;
}
// vhosts with listen 443 configs omited here, they work
我有一个不支持 HTTPS 的 IoT 客户端。因此,我将其配置为使用 HTTP 将传感器数据发送到 Nginx 服务器上的挂钩 URL。我为该本地域 xyz 添加了 VHost,它不会将请求转发到 HTTPS,而是使用纯 HTTP 进行处理。
server {
listen 80;
listen [::]:80;
server_name xyz;
server_tokens off;
location / {
root /var/www/html/;
}
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log error;
}
// vhosts with listen 443 configs omited here, they work
但是该请求从未被 Nginx 处理。
使用curl
,我得到了这个回应
# curl -v http://localhost/
* Trying 127.0.0.1:80...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.88.1
> Accept: */*
>
* Received HTTP/0.9 when not allowed
* Closing connection 0
curl: (1) Received HTTP/0.9 when not allowed
(信息:Nginx 正在监听所有设备,没有防火墙处于活动状态,当我停止服务时,Linux 中的端口被关闭...)。
journald 中、nginx 访问或错误日志中都没有错误日志消息。
然后我尝试硬核telnet
访问 80 端口,得到了更奇怪的结果:
# telnet localhost 80
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Connection closed by foreign host.
需要说明的是,我输入时GET / HTTP/1.1\n
没有第二个空行,只有一个“enter”。当我输入不符合 HTTP 规范的内容(例如随机字符串)时,服务器会响应??
。
因此,在第一行之后,Nginx 就关闭了连接(HTTP/0.9 响应来自 curl 本身)。
因为我无法Host:
在 telnet 请求中设置标头,所以此请求从未检查任何虚拟主机配置,我推测 curl 客户端也有同样的问题。它尝试将所有标头发送到套接字,但 Nginx 响应已经存在。
我不知道哪里出了问题。服务器至少应该等待 Host-header 才能关闭连接。/etc/nginx/nginx.conf
没有改变。
根据nginx -t
配置,服务器在 上响应正常curl -v https://localhost/
。SSL 配置等这里就省略了。它正在工作。
如果根本没有日志消息,还有另一种方法可以找到问题。我们知道,普通的 Nginx 就可以正常工作。因此,从 nginx 中删除所有虚拟主机配置,然后从简单的默认设置开始。
通过这样做,我可以看到 Nginx 正在按预期做出响应。
然后将刚才的虚拟主机配置逐一添加。
问题出在另一个虚拟主机配置中,它在纯 http 套接字中使用了 http2 指令。
(Debian Bookworm 上的旧 nginx 包(1.22.1)尚不支持
http2 on;
配置)http2
当删除此指令时,nginx / curl / telnet / IoT 将按预期工作。当一个非 SSL 虚拟主机使用 HTTP/2 指令时,我找不到 Nginx 无法正常工作的原因。但我可以在其他几个系统上重现它。
文档说: