Make your nginx-proxied Django site detect SSL (HTTPS)

One of the nice new features in Django 1.4 is that it allows you to (easily) detect an upstream server's use of ssl using request.is_secure().  This means that your nginx configuration can use http or https on the same server and your Django site can detect it.  The magic is accomplished by *always* setting a header on the nginx side which contains the request protocol on which the request was delivered (in your sites-available/default, for instance):

server {
listen 80 default deferred;
listen 443 default ssl;
server_name myserver.example.com;
ssl_certificate /etc/nginx/keys/server.crt;
ssl_certificate_key /etc/nginx/keys/server.key;

location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_redirect off;
proxy_pass http://app_server;
}
...
}

Then configure Django to consider that header to be an indication of ssl presence in settings.py:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')

And lastly, generate some (self-signed) ssl certificates for the server (obviously you'll need real certs for a real server):

import socket,subprocess
KEY_FILE = '/etc/nginx/keys/server.key'
CERT_FILE = '/etc/nginx/keys/server.crt'
cn = socket.getfqdn()
# Obviously you should specify your own location...
subject="/C=CA/ST=ON/L=Toronto/CN=%(cn)s"%locals()
subprocess.check_call( [
'openssl',
'req',
'-x509', '-nodes', '-days', '365',
'-subj', subject,
'-newkey',
'rsa:1024',
'-keyout', KEY_FILE,
'-out', CERT_FILE,
])

And now request.is_secure() should properly report whether the user is on http or https.  The user will (obviously) get a warning about your self-signed certificate, but better self-signed than nothing, and you can put your real keys on the server when you get them.

Comments

Comments are closed.

Pingbacks

Pingbacks are closed.