Skip to content

Instantly share code, notes, and snippets.

@epicserve
Last active May 8, 2021 06:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save epicserve/7045534 to your computer and use it in GitHub Desktop.
Save epicserve/7045534 to your computer and use it in GitHub Desktop.
Django SSL Setup Guide

Django SSL Setup Guide

Assumptions:

  • You use Django with Django-Storages for saving your STATIC and MEDIA files to S3
  • You use Nginx to reverse proxy to Django
  • You want to protect any URLs that start with /admin or /subscribe
  1. Add MediaRootS3BotoStorage to StaticRootS3BotoStorage your Django project.

  2. Update your Django settings.

    STATIC_URL = '//s3.amazonaws.com/<bucket name>/static/'
    MEDIA_URL = '//s3.amazonaws.com/<bucket name>/media/'
    DEFAULT_FILE_STORAGE = 'path.to.s3utils.MediaRootS3BotoStorage'
    STATICFILES_STORAGE = 'path.to.s3utils.StaticRootS3BotoStorage'
    THUMBNAIL_DEFAULT_STORAGE = DEFAULT_FILE_STORAGE
    AWS_S3_URL_PROTOCOL = ''
    AWS_S3_CUSTOM_DOMAIN = 's3.amazonaws.com/<bucket name>'
    AWS_S3_SECURE_URLS = False
    AWS_QUERYSTRING_AUTH = False
    AWS_ACCESS_KEY_ID = <AWS_ACCESS_KEY_ID>
    AWS_SECRET_ACCESS_KEY = <AWS_SECRET_ACCESS_KEY>
    AWS_STORAGE_BUCKET_NAME = <AWS_BUCKET_NAME>
    AWS_PRELOAD_METADATA = True
    AWS_IS_GZIPPED = False
    AWS_HEADERS = {
        'Expires': 'Thu, 19 Apr 2040 20:00:00 GMT',
        'Cache-Control': 'max-age=86400',
    }
    
  3. Setup Nginx to forward SSL requests to Django. Make sure the secure server has proxy_set_header X-Forwarded-Protocol $scheme; in the config file, so that Django request.is_secure() will work. Also make sure you read the warning about the Django SECURE_PROXY_SSL_HEADER setting. The following is a full example Nginx server config example.

    upstream example.com_app_server {
        server unix:/tmp/gunicorn_example.com.sock fail_timeout=0;
    }
    
    server {
    
        listen       80;
        server_name  example.com;
        access_log   /var/log/nginx/example.com.access.log;
        error_log    /var/log/nginx/example.com.error.log;
    
        ## Deny illegal Host headers
        if ($host !~* ^(example.com|www.example.com)$ ) {
            return 444;
        }
    
        ## Redirect example.com to www.example.com
        if ($host !~* '^www.example.com$') {
            rewrite ^/(.*)$ http://www.example.com/$1 permanent;
        }
    
        ## Custom 502 error
        error_page 502 /502.html;
        location = /502.html {
            root  /srv/sites/example.com/templates/nginx_errors;
        }
    
        ## Custom 500 error
        error_page 500 /500.html;
        location = /500.html {
            root  /srv/sites/example.com/templates/nginx_errors;
        }
    
        ## Return a 404 for the favicon
        location = /favicon.ico {
            return  404;
        }
    
        ## Redirect the admin site to https
        location /admin {
            rewrite ^/(.*)$ https://www.wenatcheeworld.com/$1 permanent;
        }
    
        ## Redirect requests starting with /subscribe
        location /subscribe {
            rewrite ^/(.*)$ https://www.wenatcheeworld.com/$1 permanent;
        }
    
        location  / {
            proxy_pass               http://example.com_app_server;
            proxy_redirect           off;
            proxy_set_header         Host             $host;
            proxy_set_header         X-Real-IP        $remote_addr;
            proxy_set_header         X-Forwarded-For  $proxy_add_x_forwarded_for;
            client_max_body_size     10m;
            proxy_buffer_size        4k;
            proxy_buffers            30 100k;
            proxy_busy_buffers_size  100k;
            proxy_intercept_errors   on;
    
            error_page 500 /500.html;
            location = /500.html {
                root  /srv/sites/example.com/templates/nginx_errors;
            }
        }
    
    }
    
    server {
    
        listen       443;
        server_name  www.example.com;
        access_log   /var/log/nginx/www.example.com.access.log;
        error_log    /var/log/nginx/www.example.com.error.log;
    
        ## SSL Settings
        ssl on;
        ssl_certificate /etc/ssl/certs/www.example.com.crt;
        ssl_certificate_key /etc/ssl/private/www.example.com.key;
        ssl_prefer_server_ciphers       on;
    
        ## Deny illegal Host headers
        if ($host !~* ^(example.com|www.example.com)$ ) {
            return 444;
        }
    
        ## Redirect example.com to www.example.com
        if ($host !~* '^www.example.com$') {
            rewrite ^/(.*)$ http://www.example.com/$1 permanent;
        }
    
        ## Custom 502 error
        error_page 502 /502.html;
        location = /502.html {
            root  /srv/sites/example.com/templates/nginx_errors;
        }
    
        ## Custom 500 error
        error_page 500 /500.html;
        location = /500.html {
            root  /srv/sites/example.com/templates/nginx_errors;
        }
    
        ## Return a 404 for the favicon
        location = /favicon.ico {
            return  404;
        }
    
        location  / {
            proxy_pass               http://example.com_app_server;
            proxy_redirect           off;
            proxy_set_header         Host                  $host;
            proxy_set_header         X-Real-IP             $remote_addr;
            proxy_set_header         X-Forwarded-For       $proxy_add_x_forwarded_for;
            proxy_set_header         X-Forwarded-Protocol  $scheme;
            client_max_body_size     10m;
            proxy_buffer_size        4k;
            proxy_buffers            30 100k;
            proxy_busy_buffers_size  100k;
            proxy_intercept_errors   off;
    
            error_page 500 /500.html;
            location = /500.html {
                root  /srv/sites/example.com/templates/nginx_errors;
            }
        }
    
    }
    
from storages.backends.s3boto import S3BotoStorage
StaticRootS3BotoStorage = lambda: S3BotoStorage(location='static')
MediaRootS3BotoStorage = lambda: S3BotoStorage(location='media')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment