All posts

Fix Load Balancer Error in Django

Troubleshoot Django errors behind load balancers including ALLOWED_HOSTS, CSRF, SECURE_PROXY_SSL_HEADER, and health check setup.

Django Behind a Load Balancer

Django is opinionated about security, which means load balancers need careful configuration. The classic symptoms are 400 Bad Request, CSRF validation failures, and redirect loops.

ALLOWED_HOSTS

Django rejects requests where the Host header doesn't match ALLOWED_HOSTS:

# settings.py
ALLOWED_HOSTS = [
    'myapp.example.com',
    'internal-alb-1234.us-east-1.elb.amazonaws.com',
    'localhost',  # for health checks hitting the pod IP
]

SSL Termination and Redirect Loops

The load balancer handles SSL, forwarding HTTP to Django. But Django's SECURE_SSL_REDIRECT sees HTTP and redirects — creating an infinite loop:

# Trust the X-Forwarded-Proto header from the LB
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
USE_X_FORWARDED_HOST = True
USE_X_FORWARDED_PORT = True

CSRF Behind a Proxy

Django 4.0+ requires CSRF_TRUSTED_ORIGINS:

CSRF_TRUSTED_ORIGINS = [
    'https://myapp.example.com',
]

Health Check Endpoint

# urls.py
from django.http import HttpResponse

def health_check(request):
    return HttpResponse("ok")

urlpatterns = [
    path('healthz/', health_check),
    # ... other urls
]

Exempt it from middleware that might interfere:

class HealthCheckMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path == '/healthz/':
            return HttpResponse('ok')
        return self.get_response(request)

Bugsly tracks those 400 and 403 errors in Django with full request metadata, making it straightforward to distinguish between misconfigured proxies and genuine attacks.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free