How to deploy django application on debian server (UWSGI version)

Install proper version of python

On debian I’d discourage using system python for deployment — mostly becaluse they tend to upgrade minor python versions without notice, which breaks C ABI in installed virtualenvs.

So either roll your own deb files that install pythons somewhere in /usr/local or compile python on server (if you frown on having developement tools on your server roll debs).

Pythonz is a nice tool to compile (and manage) many versions of python.

Install proper version of virtualenv

Note

This is more-or less irrevelant as Python (from version 3.4 onwards) has it’s own built-in virtualenv tool, so if you use non-system one it’ll have its own virtualenv.

Debian comes with ancient python/virtualenv version, and (at least on testing) it often breaks this install. If you install virtualenv locally it’ll be much more stable.

To install virtualenv locally just download virtualenv, unpack package and use virtualenv.py.

This hsa the added benefit that you can have two versions of virtualenv one for python2 and one for python3.

Install your application into virtualenv

You know how to do that don’t you?

Now you can tests whether your setup is correct, just run

./manage.py runserver

and see if you can connect to your application.

Install uwsgi into your virtualenv

Install uwsgi into your virtualenv from pip. Now you can run your application using uwsgi:

uwsgi --http :8000 --module webapp.wsgi

I strongly discourage you from using uwsgi bundled with system.

Use supervisord to launch your applicaiton

You’ll need to run your application on system start, simplest way is to use supervisord (you can install it via aptitude).

First create a script that will:

  1. Source virtualenv
  2. cd to your app directory
  3. run uwsgi.

Something along the lines:

#!/bin/bash
export HOME=/home/user
source $HOME/venv/bin/activate
cd $HOME/webapp
uwsgi --socket :8000 --module webapp.wsgi
exit $?

Notice that --http turned into --socket. Now uwsgi will speak uwsgi protocol (which should be faster than http).

Then add configuration to supervisord. All services are defined as *conf files (in ini format) inside /etc/supervisor/conf.d.

Create file containing something like:

[program:webapp]
command=/home/webapp/webapp.sh
autostart=true
autorestart=true
stderr_logfile=/var/log/webapp.err.log
stdout_logfile=/var/log/webapp.out.log
user=webapp

For all configuration options see the documentation.

Now after calling: service supervisor restart your django application should be running.

Connect uwsgi and nginx

Add following sections to nginx configuration:

upstream django {
    # server unix:///path/to/your/mysite/mysite.sock; # for a file socket
    server 127.0.0.1:8000; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      80;
    # the domain name it will serve for
    server_name .example.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste


    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /path/to/your/mysite/uwsgi_params; # the uwsgi_params file you installed
    }
}

Now you should see something on your server port 80. To finalize our setup we need to create static and media directories.

Connect ngingx and uwsgi via linux file sockets

Because of many (peformance, safety) reasons it is better to connect nginx with uwsgi via linux domain sockets.

First replace uwsgi call with something like that:

uwsgi --module webapp.wsgi --socket $HOME/sock/webapp.sock  --chown-socket=webapp-user:www-data --chmod-socket=660

This does the following: creates a socket in $HOME/sock/webapp.sock, sets its group ownership to www-data (which is user/group used by both nginx and apache on default debian configuration).

Note

Linux file sockets use normal file permissions, so nginx has to have read-write access to it.

Then replace:

upstream django {
    server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

with:

upstream django {
    server unix:///path/to/your/mysite/webapp.sock; # for a file socket
}

Update media and static root

Update settings py

You’ll need to update STATIC_ROOT, STATIC_URL, MEDIA_ROOT, MEDIA_URL settings of youe app.

Something along the lines:

MEDIA_ROOT = '/var/drigan-media'
MEDIA_URL = '/media/'
STATIC_ROOT = '/var/drigan-static'
STATIC_URL = '/static/'

Update nginx

location /media  {
    alias /path/to/your/mysite/media;  # your Django project's media files - amend as required
}

location /static {
    alias /path/to/your/mysite/static; # your Django project's static files - amend as required
}

Tweak uwsgi so it scales

You might want tweak uwsgi so it launches more processes/workers, but this well outside scope of this tutorial.