Setup Django behind uWSGI and NGINX on CentOS 7

Setting up a web server for Django could be challenging and headache. Let’s try to make it simple: Django behind uWSGI and NGINX on CentOS 7 from scratch. At the end, our complete stack of components will look like this:
the web client <-> the web server <-> the socket <-> uwsgi <-> Django

1. Install Dependencies

1.1. NGINX

yum install epel-release -y
yum install nginx -y

1.2. Python 3 & PIP

yum install python34-devel gcc -y
curl -O

1.3. Create VirtualEnv with Python3

pip install virtualenv
mkdir -p /var/www && cd /var/www
virtualenv -p python3 p3venv
If you are up-to-dated person, you can install 3.6.2 (latest python version as of now – Aug 28, 2017) follow this instruction

1.4. Install uWSGI & Django

# Activate virtual environment
source p3venv/bin/activate
pip install uwsgi
pip install django

2. Configurations

2.1. Basic NGINX config

For simplest & testing purposes, let’s create NGINX server block by issuing “vi /etc/nginx/conf.d/cioenglish.conf”. Any *.conf file inside this folder will be loaded as per instructed by main & default NGINX configuration (/etc/nginx/nginx.conf).
vi /etc/nginx/conf.d/cioenglish.conf
# Put below content in it.
# the upstream component NGINX needs to connect to
upstream django {
server unix:/var/www/cioenglish/cioenglish.sock;
# configuration of the server
server {
listen 80;
charset utf-8;
# max upload size
client_max_body_size 75M;
# Django media & static
location /media  {
alias /var/www/cioenglish/public/media;
location /static {
alias /var/www/cioenglish/public/static;
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass  django;
include uwsgi_params;
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
Save NGINX config and start NGINX service: systemctl start nginx
As of now, we have NGINX serves static files and by pass others to Django Server which will be configured shortly. It means you will get 502 bad gateway when accessing but this is totally fine.

2.2. Create Django project

# Make sure we are in right place
cd /var/www startproject cioenglish
# Also allow domain ( or IP in Django settings (/var/www/cioenglish/cioenglish/
Test if they look good by starting Django Development and uWSGI server. You will get “It worked! Congratulations on your first Django-powered page.”
python runserver ("ctrl + c" to terminate)
uwsgi --http :8000 --module cioenglish.wsgi ("ctrl + c" to terminate)
Alright, let’s configure uWSGI as service so we don’t have to keep terminal open.

2.3. Configure uWSGI as service

# Create 'uwsgi' user: unprivileged user
useradd -s /bin/false -r uwsgi
# Emperor mode
## create a directory for the vassals
- mkdir -p /etc/uwsgi/vassals
## Configuring uWSGI to run with a .ini file
vi /var/www/cioenglish/cioenglish_uwsgi.ini
### Put below content in cioenglish_uwsgi.ini
# Django-related settings
# the base directory (full path)
chdir = /var/www/cioenglish
# Django's wsgi file
module =cioenglish.wsgi:application
# the virtualenv (full path)
home = /var/www/p3venv
# Logs
logdate = True
logto = /var/log/uwsgi/access.log
# process-related settings
# master
master = true
# maximum number of worker processes
processes = 5
# the socket (use the full path to be safe)
socket = /var/www/cioenglish/cioenglish.sock;
# ... with appropriate permissions - may be needed
chmod-socket = 666
# clear environment on exit
vacuum = true
view rawcioenglish_uwsgi.ini hosted with ❤ by GitHub
Save cioenglish_uwsgi.ini file and create symlink from the default config directory to your config file
ln -s /var/www/cioenglish/cioenglish_uwsgi.ini /etc/uwsgi/vassals/
Quick test if the configuration is good by start uWSGI server and navigate to You should get “It worked! Congratulations on your first Django-powered page.”
/var/www/p3venv/bin/uwsgi --emperor /etc/uwsgi/vassals
Ctrl + C to terminate uWSGI server and let’s make it runs as a service
vi /etc/systemd/system/uwsgi.service
# Put below as its content
Description=uWSGI Emperor service
ExecStartPre=/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown uwsgi:nginx /run/uwsgi'
ExecStart=/var/www/p3venv/bin/uwsgi --emperor /etc/uwsgi/vassals
view rawuwsgi.service hosted with ❤ by GitHub
Start uWSGI and NGINX services and you should be able to access to your Django app without having to hold terminal open.
systemctl stop nginx
systemctl start uwsgi
systemctl start nginx

Real example for

How to use Django with Apache and mod_wsgi

Deployment checklist