Manoj's Blog

January 23, 20205 min read

Django Deployment in Linux Vps

Django deployment

It is easy to get started with django and hard to go on a long run and deployment is even cumbersome.

Most of the time, for development, my personal favourite is Ubuntu, for deployment, Centos is my choice as it has been a defacto standard.

The WorkFlow I use for deployment.

Setting up a VPS.

  • spin up your vps with minimal centos installation with required libraries.

    #!/usr/bin/env bash
    # Update the system
    sudo yum update
    # create a user that will deploy a django web applications.
    useradd webapps
    # Add a user to wheel group
    usermod -aG wheel webapps
    # Install epel repository
    sudo yum install epel-release
    # Install necessary libraries
    sudo "yum install Development Tools" -y
    # Install python related packages
    sudo yum install python3 python34-devel python-virtualenv python-pip
    # Install development tools
    sudo yum install vim git links
    # Install database packages
    yum install postgresql-devel postgresql-libs postgresql postgresql-server \
    postgresql-contrib -y
    # Install database driver
    sudo yum install python-psycopg2
    # Image related libraries
    sudo yum install libtiff-devel libjpeg-devel libzip-develfreetype-devel \
    lcms2-devel libwebp-devel tcl-devel tk-devel -y
    # some DNS utilities
    yum install bind-utils

Prepare postgresql database

For most of my application, I use Postgresql, so, let’s install postgresql.

# Install database packages
yum install postgresql-devel postgresql-libs postgresql postgresql-server \
postgresql-contrib -y
# Install database driver
sudo yum install python-psycopg2

After installing postgresql, let’s start postgresql server and enable postgresql for different run levels.

sudo systemctl enable postgresql
sudo systemctl start postgresql

After successful installation of postgresql, it’s time to prepare a database for our webapp. postgresql create a user postgres as a super user during installation, we will use postgres user to create database for our webapp, a database user and a database user password.

# login using postgres user
sudo su - postgres
# create a database
createdb example_db
# create a user for example_db
createuser example_user --interactive
# login to psql shell
psql example_db
# set a password for example_user
ALTER USER example_user WITH PASSWORD 'yourpassword';
# grant all privileges for example user on example_db database
GRANT ALL ON DATABASE example_db to example_user;
# quit the database
\q

Now it’s time to configure our webapp so that we can use a recently created database. Open your settings.py or any other database configuration file as per your web application architecture. Configure the following values as shown below.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'example_db',
        'USER': 'example_user',
        'PASSWORD': 'yourpassword',
        'HOST': '127.0.0.1',
        'PORT': '5432',
    }
}

Ok, we are done with database server configuration. Now its time to install and setup Gunicorn.

Gunicorn install and setup.

Issue the following commands in your centos VPS to install gunicorn.

#.
 (venv)# pip install gunicorn

After installing gunicorn, we will create a gunicorn_start.sh script to run the gunicorn server, which will ultimately controlled by supervisorctl.

On your project directory create a script called gunicorn_start.sh as shown below. This script will used to launch gunicorn server.

#!/bin/bash
# Purpose: Gunicorn starter
# Author: manojit.gautam@gmail.com
# Name of an application
NAME="Your projectname"
# project directory
PROJECTDIR=/webapps/example.com
# django project virutalenv directory
VENVDIR=/webapps/example.com/venv
# Project source directory
SRCDIR=/webapps/example.com/master/src
# Sock file as gunicorn will communicate using unix socket
SOCKFILE=$PROJECTDIR/gunicorn.sock
# User who runs the app
USER=webapps
# the group to run as
GROUP=webapps
# how many worker processes should Gunicorn spawn
NUM_WORKERS=3
# which settings file should Django use
# If you haven't spit your file it should example.settings only
DJANGO_SETTINGS_MODULE=example.settings.production
# WSGI module name
DJANGO_WSGI_MODULE=example.wsgi
# Activate the virtual environment
source $VENVDIR/bin/activate
# Export the settings module
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
# Export the python path from virtualenv dir
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
# move to src dir !IMPORTANT otherwise it won't work.
cd $SRCDIR
# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec $VENVDIR/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=debug \
  --log-file=-

After configuring gunicorn_start.sh script, we need to install and configure supervisor to manage our webapp.

Install and Configure supervisor

Install supevisor.

  # install Supervisor
  sudo yum install Supervisor
  # create the supervisor configuration script
  # you need to create this script to work
  echo_supervisord_conf > /etc/supervisord.conf
  # create the site specific configuration and include in supervisord.conf file
  # to include the below use include directives
  [include]
  files = /etc/supervisor/conf.d/*.conf

To, manage and start gunicorn_start.sh web application starter script, we need to create a web application specific configuration file.

Create a configuration file example.com.conf inside /etc/supervisor/conf.d/ directory. as shown below.

touch /etc/supervisor/conf.d/example.com.conf

Paste the following contents in example.com.conf file.

[program:example]
command=/webapps/example.com/gunicorn_start.sh              
user=webapps                                                          
stdout_logfile=/webapps/example.com/logs/gunicorn_supervisor.log   
redirect_stderr=true                                                
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8  

Install nginx

We will use Nginx as a webserver for our django web application. Issue the following commands to install nginx.

sudo yum install nginx
sudo systemctl enable nginx
sudo systemctl start nginx

Create a web server configuration file for Django web app inside /etc/nginx/conf.d/ directory as example.conf as shown below.

upstream example {
  # 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:/webapps/example.com/gunicorn.sock fail_timeout=0;
}

server{
	listen 80;
	server_name example.com;
	client_max_body_size 4G;
	access_log /webapps/example.com/logs/nginx-access.log;
	error_log /webapps/example.com/logs/nginx-error.log;


	# Robot.txt configuration
  # developers work on robot.txt more so it is suitable to push inside source code.
      	location /robots.txt {
      	  alias /webapps/example.org/robots.txt;
	}
	# Static assets configuration
 	location /static/ {
        alias   /webapps/example.com/master/src/assets/;
        expires 30d;
    	}

	# Media configuration
	location /media/ {
        alias   /webapps/example.com/master/src/media/;
        expires 30d;
    	}

        # Need to review
      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://example; #app name
        	break;
    		}
	}

        # Favicon configuration
        location /favicon.ico {
    	 alias /webapps/example.com/master/src/assets/img/favicon.ico;
	}

        # Prevent hidden files being serverd
	location ~ /\. { access_log off; log_not_found off; deny all; }

	# Error page configuration
        error_page 500 502 503 504 /500.html;
    	location = /500.html {
        root /webapps/example.com/master/src/static/;
   	 }
}

Now, restart the nginx server to load the configuration file for your django web application.

Start a web application using supervisorctl

  supervisorctl start example

To stop the web application you can use supervisorctl as shown below.

supervisorctl stop example

Manoj Gautam

Personal blog of Manoj Gautam. I’m a Backend Developer who use Python, Django and JavaScript to develop software. I have created a website that contains free text and video tutorials on computer science subjects CodeSchoolNepal.

You may follow me on twitter or join my Linkedin for latest updates.