0

I am getting an Invalid Host header error from my server and I am unsure how to address it.

The errors request URL is https://127.0.0.1:8000 and the obvious suggestion is to add localhost to my (using django) ALLOWED hosts. However I have read that keeping localhost in the allowed hosts in production is bad practice and a potential security flaw. At the moment my allowed hosts in prod is limited to my registered domain.

I have done some digging at it seems that these requests are coming from IP port scanners. In the email report I can sometimes see GitHub links in HTTP_USER_AGENT to such scanner repos. And the HTTP_X_FORWARDED_FOR is almost always either some VPN provider or located in Moscow or Beijing.

Here is my current nginx config. I have implement a few suggestions from other posts like the custom if regex filtering but it doesn't seem to have had an effect.

Apart from this issue, everything else seems to be functioning as intended. Any help would be greatly appreciated. First time setting something like this up so please point out any obvious errors.

# File: /etc/nginx/sites-available/app

server_tokens               off;
access_log                  /var/log/nginx/app.access.log;
error_log                   /var/log/nginx/app.error.log;

server {
    listen                  80 default_server;
    return                  444;
}

server {
    server_name             app.example.com;
    listen                  80;
    return                  301 https://$host$request_uri;
}

server {

    # Custom regex if statement to 444 any unexpected host header
    if ( $host !~* ^(app.example.com|example.com)$ ) {
        return 444;
    }

    location /static {
        autoindex           on;
        alias               /path/to/django/staticfiles;
    }
    
    # Pass on requests to guinicorn listening on http://localhost:8000
    location / {
        proxy_pass      http://localhost:8000;
        include         /etc/nginx/proxy_params;
        proxy_redirect  off;
    }

    listen              443 ssl;
    server_name         app.example.com;
    ssl_certificate     /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         CIPHER;
}
Tero Kilkanen
  • 34,499
  • 3
  • 38
  • 58
Atayls
  • 1
  • 2

1 Answers1

1

You are missing a default_server block for HTTPS. Therefore all requests for any host via HTTPS are passed into your app.example.com server block (I changed it to example domain).

Your configuration should look like this for the default server:

server {
    listen 80 default_server;
    listen 443 default_server ssl;

    ssl_certificate /path/to/certificate.crt;
    ssl_certificate_key /path/to/certificate.key;

    return 444;
}

I use the system's self-signed certificate / key in this block. For example, in Debian based systems there is /etc/ssl/private/ssl-cert-snakeoil.key and /etc/ssl/certs/ssl-cert-snakeoil.pem.

Then you need to remove the if block in your app.example.com block.

Tero Kilkanen
  • 34,499
  • 3
  • 38
  • 58
  • Thanks, I will give this a go. On the SSL certificate, can I simply duplicate my current SSL lines but within the modified default server block . There is no problem with having the certificate lines twice within two separate blocks? – Atayls Mar 21 '22 at 11:54
  • That is one option. – Tero Kilkanen Mar 21 '22 at 18:48