Skip to content

Instantly share code, notes, and snippets.

@sunsongxp
Forked from eliangcs/secure-django-admin.rst
Created February 4, 2018 09:59
Show Gist options
  • Save sunsongxp/0d27af9245cc22539710723ac52a68b7 to your computer and use it in GitHub Desktop.
Save sunsongxp/0d27af9245cc22539710723ac52a68b7 to your computer and use it in GitHub Desktop.
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment