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/

    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.

    set -e
    LOGDIR=$(dirname $LOGFILE)
    # user/group to run as
    cd /home/ubuntu/project
    source /home/ubuntu/project/venv/bin/activate
    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 2>>$LOGFILE
  • Nginx - /etc/nginx/sites-enabled/project

    The key parts here are that we're redirecting all requests to, 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 requests to
        listen 80;
        return 301$request_uri;
    server {
        listen   80;
        # 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;
        # 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.

    directory = /home/ubuntu/project
    user = ubuntu
    command = /home/ubuntu/project/scripts/
    stdout_logfile = /var/log/gunicorn/project-std.log
    stderr_logfile = /var/log/gunicorn/project-err.log

Read more!