![Http 请求没有被 Nginx 服务器块捕获吗?](https://linux22.com/image/724350/Http%20%E8%AF%B7%E6%B1%82%E6%B2%A1%E6%9C%89%E8%A2%AB%20Nginx%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9D%97%E6%8D%95%E8%8E%B7%E5%90%97%EF%BC%9F.png)
我有一个只有一个站点配置(默认站点)的 nginx 服务器。
我在 access.log 中不断看到以下几行
xxx.xxx.xxx.xxx - - [10/Jul/2018:16:32:14 +0200] "GET / HTTP/1.1" 400 37 "-" "-"
我知道如果请求没有发送标Host:
头,就会发生这种情况,例如curl -v -H "Host:" https://{{ server_ip }}
root@mypc:~# curl -v -H "Host:" http://{{ server_ip }}
* Rebuilt URL to: http://{{ server_ip }}/
* Trying {{ server_ip }}...
* Connected to {{ server_ip }} ({{ server_ip }}) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Server: nginx/1.14.0 (Ubuntu)
< Date: Wed, 11 Jul 2018 08:14:07 GMT
< Content-Type: text/html
< Content-Length: 182
< Connection: close
<
<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.14.0 (Ubuntu)</center>
</body>
</html>
* Closing connection 0
我确实将我的网站配置为响应没有Host:
标头的请求,错误代码为 444。显然,这不起作用。我认为我确实误解了文档,并且我的配置不正确。如果有人能指出缺少什么,我将非常高兴:
ssl_certificate /etc/letsencrypt/live/{{ hostname_fqdn }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ hostname_fqdn }}/privkey.pem;
# Respond to requests without a host header with HTTP status 444
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name "";
return 444;
}
server {
listen 80;
listen [::]:80;
server_name {{ hostname_fqdn }};
if ($allowed_country = no) {
return 444;
}
return 301 https://{{ hostname_fqdn }}$request_uri;
}
server {
listen 443 ssl;
#listen [::]:443 ssl;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
server_name {{ hostname_fqdn }};
if ($allowed_country = no) {
return 444;
}
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/{{ django_project_name }}/socket;
}
location /static/ {
root {{ django_static_root }};
}
}
server {
listen 80;
listen [::]:80;
listen 443 ssl;
#listen [::]:443 ssl;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
server_name api.zeitschrift.hausbesitzerverlag.de;
if ($allowed_country = no) {
return 444;
}
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/{{ django_project_name }}/socket;
}
location /pmx-api/ {
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/htpasswd;
limit_req zone=api burst=5;
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/{{ django_project_name }}/socket;
}
location /komtrigon-api/ {
limit_req zone=api burst=5;
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/app/{{ django_project_name }}/socket;
}
location /static/ {
root {{ django_static_root }};
}
}
答案1
不带Host:
在 HTTP/1.1(或更高版本)中无效,并且 nginx 正确地发送了 400 Bad Request 错误,甚至没有尝试使用任何 server
块。来自RFC 7230 第 5.4 节:
对于任何缺少 Host 标头字段的 HTTP/1.1 请求消息以及包含多个 Host 标头字段或具有无效字段值的 Host 标头字段的任何请求消息,服务器必须使用 400(错误请求)状态代码进行响应。
只有当请求使用古老的 HTTP/1.0 时,处理没有标头server
的请求的块才会被命中。您可以使用命令行选项来模拟这种情况:Host:
curl
-0
curl -v -0 http://203.0.113.87/
从手册页中:
-0, --http1.0
(HTTP) Tells curl to use HTTP version 1.0 instead of using its
internally preferred HTTP version.
答案2
初学者的错误。我忘了添加listen 443 ssl default_server;
到第一个服务器块。
...
server {
listen 80 default_server;
listen 443 ssl default_server;
listen [::]:80 default_server;
server_name "";
return 444;
}
...
尽管 Micheal 对 RFC 的说法完全正确,但对于 nginx 的工作方式却并不正确,因为 nginx 没有内置功能可以在这种情况下返回 400。
它也没有具体回答我的问题。由于我的 Web 服务器 10 次中有 10 次收到没有主机标头的请求,这些请求都是由垃圾邮件发送者发送的,因此我决定忽略 RFC,直接关闭连接而不让垃圾邮件发送者知道 ( return 444;
)。
答案3
我觉得你误解了一些事情。
我确实将我的网站配置为响应没有 Host: 标头的请求,错误代码为 444。显然,这不起作用。
你没有配置具体来说您的网站使用 来响应没有Host
标头的请求444
。
它是:您配置您的站点,任何与块中的host
其他值不匹配的值都将进入块。server_name
server
default_server
真正重要的是指令。您可以在块内default_server
放置任何逻辑上无效的值。server_name
default server
server
https://nginx.org/en/docs/http/server_names.html
这个名称( )没有什么特别之处
server_name ""
,它只是无数无效域名中的一个,与任何真实名称都不相交。其他无效名称(如“--”和“!@#”)同样可以使用。