Django NGINX: deploy your Django project on a production server


Wed 13 November 2019

Django NGINX is a popular and well tested combination used to deploy web applications in production. In this post I will explain the steps needed to have your Django project deployed on a production server using Ubuntu 18.04.

To have Django NGINX deployed on your production server follow these simple steps.

Django Nginx: it's better together!

Django is a web framework written in Python. It lets you develop and prototype web applications with little effort. It comes with many built-in features that are often useful in a web application, such as: session management, user authentication, an object relational mapper, a template language.

NGINX is a very fast and configurable web server that is very well suited to serve static files and act as a reverse proxy for other applications. In this tutorial I'll explain how to configure NGINX to serve static files (images, javascript, css, ...) and to proxy requests to your Django application.

Install required packages using apt

sudo apt install nginx uwsgi uwsgi-plugin-python3

Why do you need uWSGI? In very simple terms NGINX on its own cannot run a Python process to host your application, for this you’ll need a so called application server that will host a Python process running your Django project. NGINX and uWSGI will “talk” each other using the uwsgi protocol.

Create directories for your static and media files

Static files are “not-python” files needed by your Django project, for example Javascript, CSS and images. Media files will be the files uploaded by the users of your application. Not every application will let users upload files, but it’s a very common scenario. Django will not serve static and media files by itself. We’ll leverage NGINX to serve them.

First of all you have to create the directories. Here I assume that you are currently using the user ubuntu with the default home directory /home/ubuntu:

mkdir -p /home/ubuntu/static /home/ubuntu/media
sudo chown www-data.www-data /home/ubuntu/media

The second command will make the user named www-data the owner of the /home/ubuntu/media directory. www-data will be the user running your Python process in uWSGI, and that user should be able to write in the media directory to correctly save user uploaded files.

Setup your Django project and install requirements

This step really depends on your particular Django application, for the purpose of this tutorial I will assume that your Django project is installed in the directory /home/ubuntu/django_project/ with the following structure:

/home/ubuntu/django_project/
├── app1
│   ├── admin.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── views.py
├── manage.py
└── project
   ├── __init__.py
   ├── settings
  │   └── __init__.py
  │   └── base.py
  │   └── production.py
   ├── urls.py
   ├── wsgi.py

Also I will assume that you installed all your Python requirements, for example using apt or pip.

I always follow a best practice when starting a new Django project, by splitting the monolithic settings.py file in different files, one for each deploy environment (local, test, production, …). You can read a more in depth explanation of this approach if you aren’t used to it.

In our case Django will use the module project/settings/production.py for his settings. Here we set the STATIC_ROOT and MEDIA_ROOT variables to the directories we created at step 2:

from .base import *

ALLOWED_HOSTS = [ 'www.example.com' ] # customize with your domain name

DATABASES = {
    'default': { ... } # here the configuration for your database
}

STATIC_ROOT = '/home/ubuntu/static'
MEDIA_ROOT = '/home/ubuntu/media'

Collect static files

Run the following command to collect all static files for your Django project:

./manage.py collectstatic

This command will copy all static files (Javascript, CSS, images) for all your Django apps in the STATIC_ROOT directory configured in production.py. For instance /home/ubuntu/static.

Configure uWSGI to host your Django project

Create a file named django.ini in the /etc/uwsgi/apps-enabled/ directory. The content of the file should be something like this:

[uwsgi]
chdir = /home/ubuntu/django_project # customize with your django installation directory
env = DJANGO_SETTINGS_MODULE=project.settings.production # customize with your settings module
wsgi-file = project/wsgi.py # customize with the relative path to your wsgi.py file
workers = 1

Restart uWSGI with:

service uwsgi restart

You should find the uWSGI logs in /var/log/uwsgi/apps/django.log. Therefore you can check them to see if the Python process started correctly or there are issues.

Configure NGINX to serve your application

Create a file named django in the /etc/nginx/sites-enabled/ directory. The content of the file should be something like this:

server {
    listen 80;
    server_name www.example.com; # customize with your domain name

    location / {
        # django running in uWSGI
        uwsgi_pass unix:///run/uwsgi/app/django/socket;
        include uwsgi_params;
        uwsgi_read_timeout 300s;
        client_max_body_size 32m;
    }

    location /static/ {
       # static files
       alias /home/ubuntu/static/; # ending slash is required
    }

    location /media/ {
        # media files, uploaded by users
        alias /home/ubuntu/media/; # ending slash is required
    }
}

Restart NGINX with:

service nginx restart

Enjoy your Django NGINX application

Point the browser to your domain, and you should see your Django application in all of its glory!

Extra step: automate all these steps with Ansible!

If you have to manage many different Django projects on many different servers, certainly you’ll find that automating stuff is always a good idea.

Read my post on How to deploy a Django project in 15 minutes with Ansible to automate all the steps described here.

In conclusion, I hope that this post helped you with configuring Django NGINX to deploy your Django project on a production server. Please let me know if you have questions leaving a comment in the area below or contacting me by email or social account.


Share: