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 sometimes 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 development tools on your server roll debs).

Note

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

If you want deploy your server by hand just download and compile python.

If you are into automatic deployment (and you should be)

Assumptions about the system

I’ll assume that you will configure your system in following way:

  • Django application will be using www-client user
  • Code will be inside /home/www-client/repo
  • There will be a django generated uwsgi file in /home/www-client/repo/webapp.uwsgi
  • Virtualenv will be in /home/www-client/repo/venv.

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.

You can configure uwsgi using a variety of ways, most of which are better than using a command line arguments :). For example you can create an ini file named uwsgi.ini:

module=webapp.wsgi
pythonpath=/home/www-client/webapp
http=8000

And then start uwsgi using: uwsgi --ini uwsgi.ini.

Use systemd to launch your applicaiton

Now use systemd to launch the application.

Systemd is a very nice init system that is becoming a standard in most recent distributions (it’s even on Debian stable).

If your distribution has no systemd you can use supervisord (which is even on debian oldstable), tutorial to deploy django with it is here.

So create /home/webapp/uwsgi.ini file with following contents:

module=webapp.wsgi
http=8000
pythonpath=/home/www-client/repo

Create a webapp.service file and put it in /etc/systemd/system/, file should have following contents:

[Unit]
Description=Description
After=syslog.target

[Install]
WantedBy=multi-user.target

[Service]
# What process to start
ExecStart=/home/www-client/venv/bin/uwsgi --ini /home/www-client/uwsgi.ini
# What user chown to
User=www-client
# Working directory
WorkingDirectory=/home/www-client/webapp
Restart=always
# Kill by SIGQUIT signal --- this is what asks wsgi to die nicely
KillSignal=SIGQUIT
# Notify type, in this type uwsgi will inform systemd that it is ready to handle requests
Type=notify
StandardError=syslog
NotifyAccess=all

Then:

sudo systemctl --system enable webapp
sudo systemctl start webapp

Now you should have a working uwsgi configuration, which is reachable at localhost:8000.

Connect uwsgi and nginx

In this part we will put uwsgi behind nginx server.

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     /etc/nginx/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.ini file with something like:

And also create /home/www-client/sock/.

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

Now we’ll update settings so static media is served by nginx.

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.