uWSGI, Django & Nginx

It's a pain. Here's a quick run down of what I did so that I can remember to do it right the next time and not waste hours and hours configuring an app.

Best to create a new user and delete the password later.

Create a user

sudo adduser django  
# set a password here and then delete it
sudo passwd -d django  

That way we can isolate the permissions and contain an attack if need be. Anyway, onward.

Create an environment

Python3 is the way to go. Chances are, pip isn't installed. So first install setup-tools and then install pip

sudo apt install python3-setuptools  
sudo easy_install3 pip  
sudo pip install virtualenvwrapper

echo "export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3" >>  
echo "export WORKON_HOME=~/Env" >> ~/.bashrc  
echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc  
source ~/.bashrc

mkvirtualenv project --python=`which python3`  

We'll be using the environment in ~/Env and uWSGI will be pointing to that.

Configure uWSGI

Install uWSGI globally.

sudo pip3 install uwsgi

Create the uWSGI conf file at /etc/uwsgi/sites/project.ini

project = project_name  
uid = django  
base = /home/%(uid)

chdir = %(base)/%(project)  
home = %(base)/Env/%(project)  
module = %(project).wsgi:application

master = true  
processes = 5

socket = /run/uwsgi/%(project).sock  
chown-socket = %(uid):www-data  
chmod-socket = 660  
vacuum = true  
logto = /var/log/uwsgi/uwsgi.log  

NOTE: module points to wsgi file. So its' assumed that the wsgi file is inside project_name package.

And create a service so that systemctl can recognize it

Description=uWSGI Emperor service

ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown django:www-data /run/uwsgi'  
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites  


That should take care of the socket that'll be used to run the app and host for the reverse proxy (nginx). It should run it in emperor mode which will spawn vassals and they should handle the incoming requests. Anyway, next step, configure nginx. I hate this part, but the good thing is, it's pretty straight forward.


sudo apt install nginx  
sudo touch /etc/nginx/sites-available/project_name  
sudo ln -s /etc/nginx/sites-available/project_name /etc/nginx/sites-enabled/.  

And of course project conf is simply

server {  
    listen 80;
    server_name site_name;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        alias /var/www/static/;
    location /media/ {
        alias /var/www/media/;

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

Of course the path to the app is actually /home/django/project_name. Just need to chown it

sudo chown -R django:www-data /home/django/project_name.

Yeah, that does it. I should probably create an ansible playbook for this, but that's a lot of work for now.