Bad Request and Invalid HTTP_HOST header in deployment NGINX + Gunicorn + Django?

Could you, please, help me with some suggestion where or how to find a resolution of my DisallowedHost exception?

I have deployed my Django project to the DigitalOcean Ubuntu server with Nginx + Gunicorn according to instructions from DjangoProject and DigitalOcean as well as answers from related questions from DjangoForum, StackOverflow and others. I believe I tried all the advice I could find but still have 400 BadRequest responses, and Invalid HTTP_HOST header Error.

likarnet is my project name, and likarnet.com is my domain. I have connected domain likarnet.com to my public IP and SSL certificate to my domain. Versions python 3.12, django 5.0.6

Please, excuse me if I ask some obvious things. This is my first project.

File /etc/nginx/sites-available/likarnet

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name likarnet www.likarnet;

        access_log  /var/log/nginx/access.log;
        error_log  /var/log/nginx/error.log;

        location = /favicon.ico { access_log off; log_not_found off; }
        location /static/ {
            root /home/likarnet/website/likarnet;
        }

        location /media/ {
            root /home/likarnet/website/likarnet;
        }

        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-Host $server_name;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_redirect off;
            proxy_pass http://unix:/run/gunicorn.sock;
        }
}

I have just tried to use default include proxy_params;

File /etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=likarnet
Group=sudo
WorkingDirectory=/home/likarnet/website/likarnet
ExecStart=/home/likarnet/venv/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          --chdir=/home/likarnet/website/likarnet \
          likarnet.wsgi:application

[Install]
WantedBy=multi-user.target

So, when I run project with python3 manage.py runserver 127.0.0.1:8000 or 0.0.0.0:8000 and try from another terminal curl -v localhost:8000 I get

* Host localhost:8000 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8000...
* connect to ::1 port 8000 from ::1 port 59232 failed: Connection refused
*   Trying 127.0.0.1:8000...
* Connected to localhost (127.0.0.1) port 8000
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/8.5.0
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< Date: Fri, 21 Jun 2024 21:43:57 GMT
< Server: WSGIServer/0.2 CPython/3.12.3
< Content-Type: text/html; charset=utf-8
< Location: https://localhost:8000/
< X-Content-Type-Options: nosniff
< Referrer-Policy: same-origin
< Cross-Origin-Opener-Policy: same-origin
< Connection: close
< 
* Closing connection

And in terminal with project I got additional rows Host, ALLOWED_HOSTS, Domain and Port as I added printing them into function get_host() in /venv/lib/python3.12/site-packages/django/http/request.py

Host:  localhost:8000
ALLOWED_HOSTS:  ['likarnet.com', '.likarnet.com', '64.225.77.248', '127.0.0.1', 'localhost']
Domain:  localhost
Port:  8000
[21/Jun/2024 21:51:17] "GET / HTTP/1.1" 301 0

When I try curl --unix-socket /run/gunicorn.sock localhost I get

<!doctype html>
<html lang="en">
<head>
  <title>Bad Request (400)</title>
</head>
<body>
  <h1>Bad Request (400)</h1><p></p>
</body>
</html>

And I get from browser when I input likarnet.com

This site can’t be reached
likarnet.com refused to connect.
ERR_CONNECTION_REFUSED

And the ERROR Traceback from my log file. It is the same when I use browser or curl command, but with various host names - localhost, my public IP, likarnet.com or www.likarnet.com

ERROR 2024-06-21 21:51:06,961 /home/likarnet/venv/lib/python3.12/site-packages/django/core/handlers/exception.py  11561  131208492179584 Invalid HTTP_HOST header: 'localhost'. You may need to add 'localhost' to ALLOWED_HOSTS.
Traceback (most recent call last):
  File "/home/likarnet/venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/home/likarnet/venv/lib/python3.12/site-packages/django/utils/deprecation.py", line 133, in __call__
    response = self.process_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/likarnet/venv/lib/python3.12/site-packages/django/middleware/security.py", line 28, in process_request
    host = self.redirect_host or request.get_host()
                                 ^^^^^^^^^^^^^^^^^^
  File "/home/likarnet/venv/lib/python3.12/site-packages/django/http/request.py", line 151, in get_host
django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: 'localhost'. You may need to add 'localhost' to ALLOWED_HOSTS.

I am not sure which data is also important. And I am going to add everything needed. Thanks for your help and advice.

Your error is related to the ALLOWED_HOSTS in settings, because in your print output, ALLOWED_HOSTS is [....., ...., 'localhost'], but the error message states:

django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header:
localhost'. You may need to add 'localhost' to ALLOWED_HOSTS.

The validate_host method is called in the get_host method, and we are sure that 'localhost' exists in ALLOWED_HOSTS, but the error still occurs!!!

restart your gunicorn service and test it.It might be that you updated the ALLOWED_HOSTS after the service was started.

Back to Top