SSL behind an Nginx Reverse Proxy in Django 1.4

We recently upgraded one of our e-commerce websites to Django 1.4 and were pleased to find the new SECURE_PROXY_SSL_HEADER setting.

Our server is using nginx to proxy requests to Apache which serves the Django project. Therefore, Apache/Django is not aware of when incoming requests are on https. The HttpRequest.is_secure() will always return False. That means any decorators or middleware which redirect a view to a secure URL will result in an infinite redirect loop.

The solution is:

  1. Have the proxy server (nginx in our case) set the X-Forwarded-Protocol HTTP header. In the nginx config:

    proxy_set_header X-Forwarded-Protocol $scheme;
    
  2. Tell Django to use the X-Forwarded-Protocol HTTP header to determine if the request is secure. We define SECURE_PROXY_SSL_HEADER in settings.py:

    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
    

The way that works is nginx will set X-Forwarded-Protocol to "http" on normal connections and "https" on secure connections. Django's HttpRequest.is_secure() method will return True when it's set to "https".

Make sure you read the security warning for SECURE_PROXY_SSL_HEADER if you're goingn to use it.

Did you enjoy SSL behind an Nginx Reverse Proxy in Django 1.4? If you would like to help support my work, A donation of a buck or two would be very much appreciated.
blog comments powered by Disqus
Linux Servers on the Cloud IN MINUTES