Skip to content

Python Django: How to Resolve "DisallowedHost at / Invalid HTTP_HOST Header"

Fix the Django DisallowedHost error by configuring ALLOWED_HOSTS in settings.py to match your domain, IP, or subdomains, with security best practices for production and development.

When deploying a Django application, or even running one locally with a non-standard configuration, you may encounter the error DisallowedHost at / Invalid HTTP_HOST header. This is Django's security mechanism preventing your application from responding to requests with unrecognized hostnames.

In this guide, we'll explain why this error occurs, show you exactly how to fix it, and cover best practices to keep your application secure while resolving the issue.

What Does This Error Look Like?

When this error is triggered, Django displays a page like this (in debug mode):

DisallowedHost at /
Invalid HTTP_HOST header: 'your-domain.com'. You may need to add 'your-domain.com' to ALLOWED_HOSTS.

In production (with DEBUG = False), visitors will see a generic 400 Bad Request error instead.

Why Does This Error Occur?

Django includes a security feature called ALLOWED_HOSTS that validates the Host header of every incoming HTTP request. This prevents HTTP Host header attacks, where an attacker sends a request with a forged hostname to exploit your application.

The error occurs when the hostname in the incoming request doesn't match any entry in the ALLOWED_HOSTS list in your settings.py file. Common triggers include:

  • Deploying to a server without updating ALLOWED_HOSTS from the default empty list.
  • Using a reverse proxy (like Nginx or Apache) that forwards requests with a different hostname.
  • Accessing via IP address (e.g., 192.168.1.100) when only domain names are listed.
  • Running locally on a port other than the default, or accessing via 0.0.0.0.
  • Setting DEBUG = False: Django enforces ALLOWED_HOSTS strictly when debug mode is off.

How to Fix It

Step 1: Open Your settings.py File

The ALLOWED_HOSTS setting is located in your project's main settings file, typically at myproject/settings.py.

Step 2: Add Your Hostnames

Add every domain name, subdomain, and IP address that your application should respond to:


ALLOWED_HOSTS = [
    'www.example.com',    # Your primary domain
    'example.com',        # Domain without www
    '192.168.1.100',      # Server IP address (if accessed directly)
    'localhost',          # Local development
    '127.0.0.1',          # Loopback address
]

Step 3: Save and Restart Your Server

After modifying ALLOWED_HOSTS, restart your Django server for the changes to take effect:

python manage.py runserver

sudo systemctl restart gunicorn

gunicorn myproject.wsgi:application --reload

Configuration Options Explained

Specific Domain Names

List each domain and subdomain explicitly. This is the most secure approach:

ALLOWED_HOSTS = [
    'example.com',
    'www.example.com',
    'api.example.com',
]

Wildcard Subdomains

To allow all subdomains of a domain, prefix the domain with a dot:

ALLOWED_HOSTS = [
    '.example.com',  # Matches example.com, www.example.com, api.example.com, etc.
]

This is equivalent to listing every possible subdomain individually.

IP Addresses

If your server is accessed directly by IP (common during development or on internal networks), include the IP:

ALLOWED_HOSTS = [
    '10.0.0.5',
    '192.168.1.100',
]

Allow All Hosts (Wildcard *)

Using '*' allows requests from any hostname:

ALLOWED_HOSTS = ['*']

Environment-Specific Configuration

In real projects, your ALLOWED_HOSTS should differ between development and production. Here are two common patterns:

Using Environment Variables

import os

ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')

Then set the environment variable on your server:

export DJANGO_ALLOWED_HOSTS="example.com,www.example.com,192.168.1.100"

Using Separate Settings Files

ALLOWED_HOSTS = []

from .base import *
ALLOWED_HOSTS = ['localhost', '127.0.0.1']

from .base import *
ALLOWED_HOSTS = ['example.com', 'www.example.com']

Common Scenarios and Fixes

Behind a Reverse Proxy (Nginx, Apache)

When using a reverse proxy like Nginx in front of Gunicorn or uWSGI, the proxy forwards requests to Django. You need to ensure the Host header is passed correctly and the hostname is in ALLOWED_HOSTS.

Nginx configuration:

server {
    server_name example.com www.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Django settings:

ALLOWED_HOSTS = ['example.com', 'www.example.com']

Docker Containers

In Docker environments, you may access Django via the container's IP or a Docker network hostname:

ALLOWED_HOSTS = [
    'localhost',
    '127.0.0.1',
    '0.0.0.0',          # Common in Docker
    'web',               # Docker service name
    'example.com',       # Production domain
]

Elastic Beanstalk, Heroku, or Cloud Platforms

Cloud platforms assign dynamic hostnames. You'll typically need to include both the platform's hostname and your custom domain:

ALLOWED_HOSTS = [
    'your-app-name.herokuapp.com',
    'example.com',
    'www.example.com',
]

Debugging Tips

If you've added the hostname but the error persists, try these steps:

1. Check the exact hostname in the error message:

The error tells you precisely which host header was received. Copy it exactly as shown:

Invalid HTTP_HOST header: 'example.com:8080'

In this case, the port is included. You may need to add the hostname with the port, or configure your proxy to strip it.

2. Print ALLOWED_HOSTS to verify your settings loaded correctly:

print(f"ALLOWED_HOSTS = {ALLOWED_HOSTS}")

3. Check for typos and extra whitespace:

ALLOWED_HOSTS = ['example.com ', ' www.example.com']

ALLOWED_HOSTS = ['example.com', 'www.example.com']

4. Ensure you're editing the right settings file:

If your project uses multiple settings files (e.g., settings/production.py), make sure you're editing the one that's actually active:

echo $DJANGO_SETTINGS_MODULE

Quick Reference

Scenario ALLOWED_HOSTS Value
Local development ['localhost', '127.0.0.1']
Single domain ['example.com', 'www.example.com']
All subdomains ['.example.com']
IP access ['192.168.1.100']
Docker ['0.0.0.0', 'localhost', 'web']
Behind reverse proxy Domain names that Nginx/Apache forwards
Testing only (insecure) ['*']

Conclusion

The DisallowedHost at / Invalid HTTP_HOST header error is Django's built-in protection against HTTP Host header attacks.

The fix is straightforward: add the correct domain names, subdomains, and IP addresses to the ALLOWED_HOSTS list in your settings.py file, then restart your server.

For production deployments, always list specific hostnames rather than using the wildcard '*', and consider using environment variables to manage different configurations across development, staging, and production environments.

Navigation