Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Secure Django admin with self-signed SSL client certificate in Nginx.

Secure Django Admin with SSL Client Certificate in Nginx

If you need a good way to secure your Django admin site (e.g., http://example.com/admin/), this is it.

Reference: https://gist.github.com/mtigas/952344

1. Creating self-signed certificates

Find a directory to put your certificates, e.g., /etc/nginx/certs/.

Generate server certificate:

openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

Generate client certificate:

openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr

# self-signed
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

Convert client key to PKCS (for browsers):

openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

Make sure you enter an export password. Otherwise, you may be unable to import it to your browser.

2. Configure Nginx

/etc/nginx/sites-available/yoursite:

# the upstream component nginx needs to connect to
upstream django {
    #server 127.0.0.1:8000; # for a web port socket
    server unix:///tmp/uwsgi_yoursite.sock;
}

# configuration of the server
server {
    # the port your site will be served on
    listen      80;

    # the domain name it will serve for
    server_name .example.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    location /media  {
        alias /path/to/your/site/media;
    }

    location /static {
        alias /path/to/your/site/static;
    }

    location /favicon.ico {
        alias /path/to/your/site/static/img/favicon.ico;
    }

    # admin is served at port 443, return 404 on port 80
    location /admin {
        return 404;
    }

    # send all other requests to the Django server
    location / {
        include     /etc/nginx/uwsgi_params;
        uwsgi_pass  django;
    }

    # redirect error pages to Django, should provide Django views for these
    error_page 404 = /_error/404/;
    error_page 403 = /_error/403/;
    error_page 500 = /_error/500/;
    error_page 502 503 = /static/_503.html;
}

server {
    listen 443;
    ssl on;
    ssl_certificate /etc/nginx/certs/ca.crt;
    ssl_certificate_key /etc/nginx/certs/ca.key;
    ssl_client_certificate /etc/nginx/certs/ca.crt;
    ssl_verify_client on;

    location /media  {
        alias /path/to/your/site/media;
    }

    location /static {
        alias /path/to/your/site/static;
    }

    location /admin {
        include     /etc/nginx/uwsgi_params;
        uwsgi_param HTTP_X_FORWARDED_PROTO $scheme;
        uwsgi_pass  django;
    }

    # redirect other requests to http
    location / {
        return 301 http://$host$request_uri;
    }
}

3. Import client certificate

Download (with scp command) the .p12 file to your client computer.

Take Chrome browser on Mac OS for example, go to [Settings] -> [Show advanced settings]. Click [Manage certificate] button in HTTPS/SSL section. In the menu bar of Keychain Access, click [File] -> [Import Items]. Then select the .p12 file.

Restart the browser, access https://example.com/admin/, it should prompt you to choose a certificate. Select the one you just imported and you should be able to see the Django admin page successfully.

@ghost

This comment has been minimized.

Copy link

commented Jun 16, 2014

Please correct line

openssl req -new -key client -out client.csr

client -> client.key, so it would look like

openssl req -new -key client.key -out client.csr

As otherwise it generates an error

Error opening Private Key client
140139203737232:error:02001002:system library:fopen:No such file or directory:bss_file.c:404:fopen('client','re')
140139203737232:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:406:
@eliangcs

This comment has been minimized.

Copy link
Owner Author

commented Aug 17, 2014

@pete-experimenter corrected it. Thanks!

@ghost

This comment has been minimized.

Copy link

commented Nov 8, 2014

ssl_client_certificate /etc/nginx/certs/ca.crt;

Should be

ssl_client_certificate /etc/nginx/certs/client.crt;

? Fixed it for me at least!

@eliangcs

This comment has been minimized.

Copy link
Owner Author

commented Nov 12, 2014

@twined: I'm using ca.crt but it works fine?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.