Deploy Django Application using NGINX, uWSGI

After developing couple of django application and testing them using inbuild development server (runserver), I was ready to deploy my Django application to VPS but littile did I know, deployment of django application is a big task itself.

I first started using official tutorial from Digital Ocean How To Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 16.04 but it turned out to be two complex. I spent almost a day but I ended up nowhere. I was searching for otherway of deployment thats when I came across uWSGI. You can find official documentation here. Setting up Django using uWSGI was not cakewalk either but I found it easy as compared to Gunicorn. In this effort, i spent almost two days (not whole days, may be  hours in total) but finally I got it working. I am documenting step by step actions for you to help.

Step#1 Prepare environment

$sudo apt-get update
$sudo apt-get upgrade
$sudo python3.6 -m pip install virtualenv

Now let us create a django application on server. If you have already developed your application, you can deploy it to server using git as explained here or copy code using FileZilla or some other ways. For simplicity, I am creating an application.

$django-admin startproject yourapp
$cd yourapp
$python3.6 manage.py startapp blog
$virtualenv venvft
created virtual environment CPython3.6.4.final.0-64 in 453ms
creator CPython3Posix(dest=/var/www/yourapp/venvft, clear=False, global=False)
seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, via=copy, app_data_dir=/home/user/.local/share/virtualenv/seed-app-data/v1.0.1)
activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator

$source venvft/bin/activate
$pip install django 
$pip install psycopg2
deactivate

Please note the packages are installed inside virtual environment using pip install but outside it using command $sudo python3.6 -m pip install psycopg2. This command will not work inside virtual environment. Please don’t ask me why, I only know how. You can deactivate virtual environment at this stage.

Step#2 Django Application set up.

You already know what you need to do to set up django application. Changes to settings.py etc. For more details, you can refer to this post Building blog application using django.

Once basic setup is done, you need to run following commands

$ python3.6 manage.py makemigrations blog
$ python3.6 manage.py migrate

Before we test the application, please update ALLOWED_HOSTS in settings.py. Here ‘NNN.NN.NN.NNN’ stands for your server ip

ALLOWED_HOSTS = ['NNN.NN.NN.NNN','www.domain.com','domain.com','localhost','127.0.0.1','0.0.0.1']

Once done, let us test our application using our old development server. This is to ensure, our application is working fine. If you face any issue at this stage, it has nothing to do with server setup, tourbleshoot any Django related issue here. Only if you can run your application on development server, proceed to next step

python3.6 manage.oy runserver

You can open new command prompt and test this using following

curl http://127.0.0.1:8000/

Step#3 Run using uWSGI server

Now lets run it using uwsgi using following command

sudo uwsgi --http 0.0.0.0:8000 --home /var/www/yourapp/venvft --chdir /var/www/yourapp/yourapp --wsgi-file /var/www/yourapp/yourapp/wsgi.py

Toubleshooting. There is possibility that you might get below error

ModuleNotFoundError: No module named 'yourapp'
unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 28959, cores: 

In this case, you need to make few changes to yourapp/yourapp/uwsgi.py file

import os
import sys #added this

from django.core.wsgi import get_wsgi_application

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #added this
sys.path.append(BASE_DIR) #added this

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yourapp.settings')

application = get_wsgi_application()

I have added comments about which line needs to be added. Now test again and it should work file.

Step# 4 uWSGI setup

Create a yourapp.ini file @ location /home/username/uwsgi/sites as below

[uwsgi]
home = /var/www/yourapp/venvft
chdir = /var/www/yourapp/yourapp
wsgi-file = /var/www/yourapp/yourapp/wsgi.py

#http = 0.0.0.0:8000

socket = /run/uwsgi/yourapp.sock
vacuum = true
chown-socket = username:www-data
chmod-socket = 666

Please change yourapp and username in this file as pr your names

Now cd /etc/systemd/system/ and sudo nano uwsgi.service

[Unit]
#Description=uWSGI Emperor service
Description=uWSGI Emperor

[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown username:www-data /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /home/username/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

Here also. change the username to match yours.

After this is done cd /var/www/ and change ownership of project folder

sudo chown www-data:www-data -R yourapp

Step#5 NGINX setup

This is simplest of all. Simply use following code.

server {
    server_name yourdomain.com www.yourdomain.com;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/yourapp.sock;
        }
}

Now run following commands

sudo service nginx stop
sudo service uwsgi stop
sudo service nginx start
sudo service uwsgi start

Restart can also work but I prefer to stop and start.

Now before you check your application on your browser cd /run/uwsgi
and check if this folder has any files

If there is no error you will see filename yourapp.sock. Now you are all set to access your application using its domain name.

Following links were very helpful for me. If you need any clarification or facing error, you can let me know or check below links

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.