I have an nginx server with exactly one site configuration (the default site).
I keep seeing the following lines in my access.log
xxx.xxx.xxx.xxx - - [10/Jul/2018:16:32:14 +0200] "GET / HTTP/1.1" 400 37 "-" "-"
I know for a fact that this happens if the request doesn't send a Host:
header, as in 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
I did configure my site to respond to requests with no Host:
header with an 444 error code. Obviously, this doesn't work. I assume I did misunderstand the docs and my config is incorrect. I would be glad if someone could point out what's missing:
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 }};
}
}
HTTP requests without a
Host:
header are not valid in HTTP/1.1 (or later), and nginx is correctly sending a 400 Bad Request error without even attempting to serve it with anyserver
block. From RFC 7230 section 5.4:Your
server
block which serves requests without aHost:
header will only be hit when a request comes in with the ancient HTTP/1.0. You can simulate this usingcurl
with the-0
command line option:From the man page:
Beginner's mistake. I forgot to add
listen 443 ssl default_server;
to the first server block.Although Micheal is completely correct about the RFC, it wasn't true in regards on how nginx works, as nginx has no built-in functionality that returns a 400 in that case.
It also didn't specifically answer my question. Since 10 out of 10 times my web server receives a request without host header, the request is sent by a spammer, I decided to ignore the RFC and just close the connection without letting the spammer know (
return 444;
).I think you misunderstood something.
You does not configure specifically your site to respond to requests with no
Host
header with444
.It is: you configure your site that any
host
value that do not match otherserver_name
value inserver
blocks, will come to thedefault_server
block.It's the
default_server
directive that actually matters. you can put any logically invaild value inserver_name
, within thedefault server
,server
block.https://nginx.org/en/docs/http/server_names.html