This tutorial will setup a Django environment running with nginx as a reverse proxy for the app. A gunicorn server will run our Django app i.e. gunicorn will act as a WSGI server. To ensure that this server runs continously and on boot, we will use supervisor to control that gunicorn process, thus avoiding pesky screen tricks.

Login to your server with a normal user, say aatish. The user should have sudo privileges. If you are currently using root account, stop right now and create a new account with the following commands:

create a normal user (skip if you are not root)

adduser aatish
adduser aatish sudo
su django

Now on, we will use sudo when needed.

Install requirements

sudo apt-get update
sudo apt-get install nginx python-pip libjpeg-dev zlib1g-dev build-essential libpq-dev python-dev supervisor python-virtualenv git

Create a directory where the code will be kept

cd ~
mkdir -p webapps/
cd webapps/

We don't want to install Python packages required by the app system-wide. So, let's create a new virtualenv under it:

virtualenv venv

or if you are using python3

virtualenv -p python3 venv

Activate the created virtual environment with:

source venv/bin/activate

Now clone your app into the server with:

git clone

Substitute the URL with yours.

Edit inside the app if needed.

To install Python packages that your app requirements, do this inside the app:
cd django-poll-app
pip install -r requirements.txt

If you don't have requirements.txt inside the app, create one and list all the dependencies. You can learn more about this at

PostgreSQL database (skip if not needed)

If you need to use PostgreSQL database, install it using:

sudo apt-get install libpq-dev python-dev postgresql postgresql-contrib python-psycopg2

Now, create a new database for use with Django with:

sudo su postgres
createdb djangodbname;
createuser -P djangodbuser;
GRANT ALL PRIVILEGES ON DATABASE djangodbname TO djangodbuser;

Set your password when prompted and type \q to quit.

Update these settings inside your file. You will now need to run migrations with:

python migrate

If you are using Django Admin:

python createsuperuser

Using gunicorn

Running Django's development server is not recommended in production. We are going to use Gunicorn for that. Install it using:

pip install gunicorn

Create a script under ~/webapps/ Paste the following contents inside it:

# Modified from
DJANGO_SETTINGS_MODULE=mysite.settings      # which settings file should Django use
DJANGO_WSGI_MODULE=mysite.wsgi              # WSGI module name

echo "Starting $NAME as `whoami`"

# Activate the virtual environment
source $ACTIVATE

# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec $GUNICORN ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=warning \
  --log-file=- \
--pid $PIDFILE

Make this script executable with:

chmod +x

Create a new file /etc/supervisor/conf.d/ with the following contents:

command = /home/aatish/webapps/  ; Command to start app
user = aatish                                     ; User to run as
stdout_logfile = /home/aatish/webapps/   ; Where to write log messages
redirect_stderr = true                              ; Save stderr in the same log
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8     ; Set UTF-8 as default encoding

Ask supervisor to reread and start the app with:

supervisorctl reread
supervisorctl update

Create a file /etc/nginx/sites-available/ with the following contents:

upstream django_poll_app_server {
  # fail_timeout=0 means we always retry an upstream even if it failed
  # to return a good HTTP response (in case the Unicorn master nukes a
  # single worker for timing out).

  server unix:/home/aatish/webapps/ fail_timeout=0;

server {

    listen   80;
    server_name; # you can use _ if you donot have a domain

    client_max_body_size 80M;

    access_log /home/aatish/webapps/;
    error_log /home/aatish/webapps/;

    location /static/ {
        alias   /home/aatish/webapps/;

    location /media/ {
        alias  /home/aatish/webapps/;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;

        if (!-f $request_filename) {
            proxy_pass http://django_poll_app_server;

    # Error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /home/aatish/webapps/;

Add it to sites-enabled using:

cd /etc/nginx/
ln -s /etc/nginx/sites-available/ sites-enabled/

Restart the nginx process using:

service nginx restart

Any log files should be available at ~/webapps/
You should be able to browse your Django app at

That's it. Enjoy.

Celery configuration

If you need to use celery, add it to requirements and create a file /home/aatish/webapps/ with the following contents:

/home/aatish/ worker --app=mysite -l warn

Also, create a supervisor configuration /etc/supervisor/conf.d/example.com_celery.conf with the contents:


If you use RabbitMQ as broker, install it using:

sudo apt-get install rabbitmq-server

Restart supervisor with:

sudo supervisorctl reread
sudo supervisorctl update

Your celery server is now running. Enjoy async.