Deployment

Alright, so you’ve made it this far. The gist of what I did for deployment is use DigitalOcean’s one-click installer to pave the way, and then modify the scripts it generated to work with Django 1.7 and Python 3.4. So to start, you can use the one-click Django droplet creator on DigitalOcean’s website.

Once finished with that, you have a few different options for editing the files. You can SSH in and edit them with something like nano or vim. Or, you can download the files over SFTP, edit them locally, and then upload to your server.

Github and virtualenv

I’ve been managing my project this entire time using Git, and then pushed it to Github. If you aren’t already managing your project with Git, go ahead and get that set up and pushed to Github. Next, you will need to recreate your virtualenv setup on your server and clone your Github project into it. The combination of virtualenv and Github is nice because you can ensure that your local development environment is nearly identical to your server environment, and it’s really easy to pull changes you make. Remember, Python is an interpreted programming language so we don’t need to compile anything. Files that we pull in from Github to our production server will instantly be used!

Gunicorn

Gunicorn, short for Green Unicorn, is “a Python WSGI HTTP Server for UNIX”. This is what will serve our Django project. Install gunicorn to your virtualenv. DigitalOcean already set us up with a basic config file, but we’ll need to edit it to our taste. Go ahead and edit /etc/init/gunicorn.conf to look like this:

description "Gunicorn daemon for Django project"

start on (local-filesystems and net-device-up IFACE=eth0)
stop on runlevel [!12345]

# If the process quits unexpectedly trigger a respawn
respawn

setuid django
setgid django
chdir /var/www/<your vitualenv>

exec bin/gunicorn \
    --bind=0.0.0.0:9000 \
    Django.wsgi:application # Wherever your wsgi file is located

I’m not an expert with gunicorn, but this is how I got it to work. Note that we are having it run on port 9000.

nginx

DigitalOcean has also setup nginx to act as a reverse proxy in front of gunicorn. nginx will improve performance by handling stuff such as serving our static assets. Go ahead and edit the /etc/nginx/sites-enabled/django file to look like so:

upstream app_server {
    server 127.0.0.1:9000 fail_timeout=0;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html;
    index index.html index.htm;

    client_max_body_size 4G;
    server_name _;

    keepalive_timeout 5;

    # Your Django project's media files - amend as required
    location /media  {
        alias /var/www/<your_project>/media;
    }

    # your Django project's static files - amend as required
    location /static {
        alias /var/www/<your_project>/static; 
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server;
    }
}

Again note how we are using port 9000. :) During my research on this I noticed lots of debate for where to put the static and media folders. I’m not using the media folder for anything so I let it be. I decided to keep the static folder inside of my project directory so that it would be included as part of Git. Someone can correct me if that’s not a good enough reason.

PostgreSQL

I’m using PostgreSQL as my database and DigitalOcean already has that configured. Just use the name and password that they have set up for you. Make sure that you have the correct dependencies installed in your virtualenv, such as psycopg2.

Static files

We’ve already configured our static files in nginx, but we still need to configure our settings.py file. Add the following lines:

STATIC_ROOT = '/var/www/<your_project>/static/'
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"), )

Try it out

Before trying out your server make sure to restart your nginx and gunicorn services. Simply run:

service nginx restart
service gunicorn restart

Hopefully you should be able to access your blog now, unless I forgot a step! Please let me know if something is not working, though most issues should be obvious (missing dependency, etc). You can view gunicorn logs at /var/log/upstart/gunicorn.log and nginx logs at /var/log/nginx/error.log.

Finishing up

There’s still some things to do in order to make your server “production ready”. For example, you need to set DEBUG = False and add entries to ALLOWED_HOSTS in your settings.py file. You probably want to read your SECRET_KEY in from an environment variable rather than having it hardcoded in the file. All of these are out of the scope of this tutorial though, so continue Googling!

Sources

Do some further reading here and here.

Disclaimer

I’m not a server admin or anything, just a software engineer that knows his way around a terminal and intermediate Linux. I would use this as a start, but I definitely recommend you doing further research on your own.