Django Server Setup

This tutorial will show you how to serve a Django application by using PostgreSQL, Gunicorn, and NGinx on an Ubuntu server. I created this tutorial because when I started configuring my server, I had a lot of trouble finding anything useful when it came to serving Django apps built in Python 3. I found that virtually all the tutorials I could find still insisted on using Python 2. So, this will show you how to turn your Python 3 Django app into a fully fledged website. This tutorial uses the following software with the corresponding versions:

  • Ubuntu 14.04.1 LTS
  • Nginx 1.4.6
  • Python 3.4.0
  • Django 1.5
  • Gunicorn 19.3

The only thing that I am going to assume is that you already have an up-to-date Ubutnu 14.04 server running. The rest of the tutorial will take you through each and every step.

Install NGinx

NGinx (pronounced Engine-X), is a lightweight web server. We will be using it to serve our static files and to proxy requests to Gunicorn. To install NGinx, issue the following command:

sudo apt-get install nginx

Install PostgreSQL

PostgreSQL is an open source database system that we will setup Django to use. To install PostgreSQL, we first need to install some dependencies that Django requires to work with PostgreSQL.

sudo apt-get install libpq-dev python-dev

Then, install PostgreSQL with the following command, then switch to the Postgres user.

sudo apt-get install postgresql postgresql-contrib
sudo su - postgres

Then create a new database:

createdb mydb

Additionally, you should create a new user also:

createuser -P [username]

Lastly, grant the new user access to the database:

psql
GRANT ALL PRIVILEGES ON DATABASE mydb TO username;
\q
logout

Setting Up Your Virtual Environment

Create a new virtual environment

A Python virtual environment allows you to run different versions of Python on the same server. It also has the benefit of allowing you to separate the dependencies of different apps, because they are completely different Python installations. Change directories to the directory you want your virtual environment to be. I’ve found that the recommended place to put your virtual environments is in /opt/env/, where env/ contains one or many python virtual environments.

cd /opt/env

Starting in Python 3.3, a tool named venv, or pyvenv, has been being shipped with Python 3 installations. However, Python 3.4 shipped with a broken version of pyvenv which leads to some errors when it tries installing things. To counter this, we can install the virtual environment with the following commands, replacing the string “myvenv” with your chosen virtual environment folder name:

pyvenv-3.4 --without-pip myvenv
source ./myvenv/bin/activate
wget https://pypi.python.org/packages/source/s/setuptools/setuptools-3.4.4.tar.gz
tar -vzxf setuptools-3.4.4.tar.gz
cd setuptools-3.4.4
python setup.py install
cd ..
wget https://pypi.python.org/packages/source/p/pip/pip-1.5.6.tar.gz
tar -vzxf pip-1.5.6.tar.gz
cd pip-1.5.6
python setup.py install
cd ..

In order to use the virtual environment, you need to activate it using the command source ./myvenv/bin/activate. When activated, all python commands will execute through this virtual environment. To deactivate the virtual environment, run deactivate.

Be careful using sudo when executing Python scripts meant to be run in your virtual environment. When you execute a python script with sudo, your virtual environment will not be active in the scope that the script is run in. So it may actually be better to issue a su command first, activate the virtual environment, and then run the Python command. Or better yet, set the permissions to your directories correctly so root access isn’t needed.

Install Python Packages

First, make sure your virtual environment is activated. If it is not, run source ./myvenv/bin/activate. Then, install Django with:

pip install django

After Django successfully installs, install Gunicorn, the Python web server.

pip install gunicorn

Lastly, install the python connector for PostgreSQL.

pip install psycopg2

If your application has any other dependencies, you may as well take a minute now to install them.

Create a Django Project

If you would like to import an existing Django project, you should do so here. However, if not, then create a new project. The location of your project is entirely up to you. From what I’ve found, it’s recommended to put your django project in /opt/env/myvenv/mysite, where mysite is your Django project. However, I like to put my projects in /var/www/project_name/mysite. Anyways, first make sure the virtual environment is activated:

source ./myvenv/bin/activate

Then, create the new Django project:

django-admin.py startproject mysite

Configure the Django Project

Edit settings.py to contain the following database settings:

DATABASES = {
  'default': {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'NAME': 'mydb',
    'USER': 'username',
    'PASSWORD': 'password',
    'HOST': 'localhost',
    'PORT': ''
  }
}

Now, sync the database by navigating to the same directory as your manage.py file, and running:

python manage.py syncdb

Configure Gunicorn

Create a gunicorn_config.py file; I like to place this at:/opt/env/myvenv/gunicorn_config.py. Add the following:

command = '/opt/env/myvenv/bin/gunicorn'
pythonpath = '/opt/env/myvenv/mysite'
bind = '127.0.0.1:8001'
workers = 3

Save the file and run the following command to start Gunicorn with the above settings:

/opt/env/myvenv/bin/gunicorn -c /opt/env/myvenv/gunicorn_config.py mysite.wsgi

Configure NGinx

If NGinx is not already running, start it with:

sudo service nginx start

Then, in your settings.py file, set your STATIC_ROOT to the path that you want to host static files at. For me, this would be /var/www/project_name/static. Now, we are going to configure the site in Nginx. Create a new file /etc/nginx/sites-available/project_name and edit it to contain the following:

server {
  server_name yourdomainorip.com;

  access_log off;

  location /static/ {
    alias /var/www/project_name/static/;
  }

  location / {
    proxy_pass http://127.0.0.1:8001;
    proxy_set_header X-Forwarded-Host $server_name;
    proxy_set_header X-Real-IP $remote_addr;
    add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
  }
}

This does two things:

  1. Serves the static files folder
  2. Forwards requests to Gunicorn

Now, we need to create a symbolic link to the above file:

cd /etc/nginx/sites-enabled
sudo ln -s ../sites-available/project_name

You may also want to remove the default configuration in this directory. Restart NGinx with sudo service nginx restart
The site should now work, so long as your Gunicorn server is running.

Automate Gunicorn with Supervisor

We obviously don’t want to have to manually start the Gunicorn server all the time, so we’re going to automate it using supervisor. First, install supervisor:

sudo apt-get install supervisor

Let’s create a start script for gunicorn at /opt/env/myvenv/gunicorn_start:

#!/bin/bash

#activate the virtual environment
source /opt/env/myvenv/bin/activate
#launch gunicorn
/opt/env/myvenv/bin/gunicorn -c /opt/env/myvenv/gunicorn_config.py mysite.wsgi

After gunicorn_start is saved, make it executable using your preferred method. To get it working, you can run chmod +x gunicorn_start, but you should consider more strict permissions for production servers.
Then, create a new file at /etc/supervisor/conf.d/mysite.conf with the following contents:

[program:mysite]
command=/opt/env/myvenv/gunicorn_start
autostart=true
autorestart=true

Gunicorn should now start automatically, and your Django website should be live!

Sources:

If you have any suggestions or problems with this tutorial, please let me know by using some form of contact method which can be found on my home page.