After yet another attempt to deploy a Django application I decided to document the steps required to get everything up and running. The tutorials I’ve seen tend to focus on individual pieces rather than on the way all these packages work together which always led to me a lot of dead ends and StackOverflow so this will hopefully address some of those issues.

In particular, I want to focus on the configuration rather than the installation of the various packages since that’s covered in the package documentation.

I don’t know if this is the best way to deploy Django but it’s the approach I’ve been able to come up with by stumbling around and getting help from the docs, Google, and StackOverflow. If there are better ways out there please let me know.

  • Gunicorn- /home/ubuntu/project/scripts/start.sh

    The nice thing here is that we define the port to serve our application on so we can serve multiple projects on a single server with each one using a different port. Note that the settings approach used here is from Two Scoops of Django.

    #!/bin/bash
    set -e
    DJANGODIR=/home/ubuntu/project
    DJANGO_SETTINGS_MODULE=project.settings.prod
    
    LOGFILE=/var/log/gunicorn/guni-project.log
    LOGDIR=$(dirname $LOGFILE)
    NUM_WORKERS=3
    # user/group to run as
    USER=ubuntu
    GROUP=ubuntu
    cd /home/ubuntu/project
    source /home/ubuntu/project/venv/bin/activate
    
    export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
    export PYTHONPATH=$DJANGODIR:$PYTHONPATH
    
    test -d $LOGDIR || mkdir -p $LOGDIR
    exec /home/ubuntu/project/venv/bin/gunicorn_django -w $NUM_WORKERS \
      --user=$USER --group=$GROUP --log-level=debug \
      --log-file=$LOGFILE -b 0.0.0.0:8001 2>>$LOGFILE
  • Nginx - /etc/nginx/sites-enabled/project

    The key parts here are that we're redirecting all www.project.com requests to project.com, serving the static files using Nginx rather than rely on Gunicorn, and passing other requests to the Gunicorn server running on the port defined in the Gunicorn start script above.

    server {
        # Redirect all www.project.com requests to project.com
        listen 80;
        server_name www.project.com;
        return 301 http://project.com$request_uri;
    }
    
    server {
        listen   80;
        server_name project.com;
        # no security problem here, since / is alway passed to upstream
        root /home/ubuntu/project/;
        # serve directly - analogous for static/staticfiles
        location /media/ {
            # if asset versioning is used
            if ($query_string) {
                expires max;
            }
        }
        location /admin/media/ {
            # this changes depending on your python version
            root /home/ubuntu/project/venv/lib/python2.7/site-packages/django/contrib;
        }
        location /static/admin {
            autoindex on;
            root   /home/ubuntu/project/venv/lib/python2.7/site-packages/django/contrib/admin/;
        }
        location /static/ {
            autoindex on;
            alias   /home/ubuntu/project/assets/;
        }
        location / {
        # This section is to redirect all http traffic to https if desired
        # if ($http_x_forwarded_proto != 'https') {
        #   rewrite ^ https://$host$request_uri? permanent;
        # }
    
            client_max_body_size 5M;
            client_body_buffer_size 128k;
            proxy_pass_header Server;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Scheme $scheme;
            proxy_connect_timeout 300;
            proxy_read_timeout 300;
            proxy_pass http://127.0.0.1:8001/;
        }
        # what to serve if upstream is not available or crashes
        error_page 500 502 503 504 /media/50x.html;
  • Supervisord - /etc/supervisord/gunicorn-project.conf

    Here we just specify the location of the Gunicorn start script so Supervisor can manage it.

    [program:gunicorn-project]
    directory = /home/ubuntu/project
    user = ubuntu
    command = /home/ubuntu/project/scripts/start.sh
    stdout_logfile = /var/log/gunicorn/project-std.log
    stderr_logfile = /var/log/gunicorn/project-err.log

Read more!