Alex Rivera | Logout

How to deploy an HTTPS-only site, with Django/nginx?

Asked 2011-11-16T15:09:52.850
44

My original question was how to enable HTTPS for a Django login page, and the only response, recommended that I - make the entire site as HTTPS-only.

Given that I'm using Django 1.3 and nginx, what's the correct way to make a site HTTPS-only?

The one response mentioned a middleware solution, but had the caveat:

Django can't perform a SSL redirect while maintaining POST data. Please structure your views so that redirects only occur during GETs.

A question on Server Fault about nginx rewriting to https, also mentioned problems with POSTs losing data, and I'm not familiar enough with nginx to determine how well the solution works.

And EFF's recommendation to go HTTPS-only, notes that:

The application must set the Secure attribute on the cookie when setting it. This attribute instructs the browser to send the cookie only over secure (HTTPS) transport, never insecure (HTTP).

Do apps like Django-auth have the ability to set cookies as Secure? Or do I have to write more middleware?

So, what is the best way to configure the combination of Django/nginx to implement HTTPS-only, in terms of:

  • security
  • preservation of POST data
  • cookies handled properly
  • interaction with other Django apps (such as Django-auth), works properly
  • any other issues I'm not aware of :)

Edit - another issue I just discovered, while testing multiple browsers. Say I have the URL

Edit
Report

1 Answer

21

Here is the solution I've worked out so far. There are two parts, configuring nginx, and writing code for Django. The nginx part handles external requests, redirecting http pages to https, and the Django code handles internal URL generation that has an http prefix. (At least, those resulting from a HttpResponseRedirect()). Combined, it seems to work well - as far as I can tell, the client browser never sees an http page that the users didn't type in themselves.

Part one, nginx configuration

# nginx.conf
# Redirects any requests on port 80 (http) to https:
server {
    listen       80;
    server_name  www.mysite.com mysite.com;
    rewrite ^ https://mysite.com$request_uri? permanent;
#    rewrite ^ https://mysite.com$uri permanent; # also works
}
# django pass-thru via uWSGI, only from https requests:
server {
    listen       443;
    ssl          on;
    ssl_certificate        /etc/ssl/certs/mysite.com.chain.crt;
    ssl_certificate_key    /etc/ssl/private/mysite.com.key;

    server_name  mysite.com;
    location / {
        uwsgi_pass 127.0.0.1:8088;
        include uwsgi_params;
    }
}

Part two A, various secure cookie settings, from settings.py

SERVER_TYPE = "DEV"
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True # currently only in Dev branch of Django.
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

Part two B, Django code


                        
                        
answered 2011-11-18T14:46:19.257

Your Answer