blog-image

May 20, 2024

14 min read

How to Create and Deploy a Django Application Using uWSGI and Nginx on Ubuntu 22.04

Written by

Abdelhadi Dyouri

Introduction

Django is a web framework that allows you to create web applications using the Python language. uWSGI is a Python Web Server Gateway Interface HTTP server, allowing you to serve your Python web application in an efficient, production-ready environment. NGINX is an open-source web server delivering web content through the internet, as well as reverse proxying, caching, load balancing, media streaming, and more.

This tutorial will show you how to create a small Django application, serve it using uWSGI, and configure Nginx as a reverse proxy that sits in front of uWSGI and forwards client requests to it, which improves scalability, performance, resilience, and security.

Prerequisites

To follow this tutorial you need:

  • Basic knowledge of the Linux command line.
  • An Ubuntu 22.04 server with a non-root user with sudo privileges. You can get affordable, and powerful Ubuntu servers from our website, and you can check out our How to access your server using SSH guide to learn how to access your server and create a sudo user.
  • Nginx installed on your Ubuntu server, follow our Installing LEMP on Ubuntu 22.04 guide to install it on your server.

Update The Package Cache

Start by updating the packages in the package manager cache to the latest available versions using the following command:

sudo apt update

Installing Core Dependencies

Before you start writing your Django application, you need to install some core dependencies for your Python programming environment. To do this, use the following command:

sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools python3-venv

With this, you can now create a Python virtual environment for your project.

Creating a Django Application Inside a Virtual Environment

Before you install Django and uWSGI, you will first create a project folder and then create a Python virtual environment inside it to isolate your project code and dependencies from the rest of the system.

Python virtual environments allow you to have multiple isolated Python environments on one computer. This is useful for projects that require different versions of Python, or for projects that you don't want to contaminate with code from other projects. This ensures that each Python project is isolated from your other projects, so that conflict between dependencies does not occur.

First, create the project folder, we'll call it myapp:

mkdir myapp

Navigate to it:

cd myapp

Create a Python virtual environment inside your myapp project folder:

python3 -m venv env

Activate it:

source env/bin/activate

Your command line should now have an (env) prefix indicating that your virtual environment is activated.

Install Django and uWSGI:

pip install django uwsgi

With Django and uWSGI now installed, you can now create a small application.

Building a Small Django Application

We'll create a small Django application that displays a Hello World! web page.

First, in your myapp folder, create a new Django project using the Django admin:

django-admin startproject mysite

This creates a new mysite directory containing the Django files that are needed for our demo application.

Navigate to this new mysite folder:

cd mysite

Next, create a new application inside this Django project with the following command:

python manage.py startapp app

This will create a new django application and a new directory called app.

Before you create your application, you need to adjust your project settings to disable debugging and allow your server IP and domain names as hosts to serve your application. Open the mysite/settings.py file:

nano mysite/settings.py

Set the DEBUG = True line to this:

DEBUG = False

Then, set the ALLOWED_HOSTS line to the following:

ALLOWED_HOSTS = ['your_domain', 'your_IP_address', 'localhost']

Save and close the file.

Note: Remember to replace your_domain and your_IP_address with your own appropriate values.

Next, open app/views.py to add a new view:

nano app/views.py

Add the following code to it:

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello Wrold! This is my Django app!")

Save and close the file.

Next, create a file called urls.py to reference this new view:

nano app/urls.py

Add the following to it:

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

Save and close the file.

Next, open the main mysite/urls.py:

nano mysite/urls.py

Then include the app/urls.py file in it by importing the include function from django.urls and calling the path() function and passing it the app.urls module like so:

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('', include('app.urls')),
    path('admin/', admin.site.urls),
]

Now, allow port 8000 on your firewall and then run the Django development server:

sudo ufw allow 8000
python manage.py runserver 0.0.0.0:8000

You should receive the following as part of the output:

Django version 4.1.3, using settings 'mysite.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

This confirms that our Django application is running. Navigate to it with the following URL, replacing your_IP_address with your server's IP address:

your_IP_address:8000

You should see the Hello Wrold! This is my Django app! text.

Configure uWSGI

Now that you've set up your sample Django application, you can set up uWSGI.

Inside your mysite project, activate the environment if you haven't already.

Run the application with uWSGI by giving it the 0.0.0.0:8000 interface and the project's WSGI module.

uwsgi --socket 0.0.0.0:8000 --protocol=http -w mysite.wsgi:application

Now use your browser to visit your applications URL again:

http://your_server_ip:8000

You'll see the Hello Wrold! This is my Django app! text on your browser.

With this, you have ensured the uWSGI server is functioning correctly.

Setting up a uWSGI Configuration File

Now that the uWSGI server is functioning correctly, create a uWSGI configuration file inside your mysite project directory, where the manage.py file exists. Call this configuration file myapp.ini:

nano myapp.ini

Add the following configuration to it:

[uwsgi]
module = mysite.wsgi:application

master = true
processes = 5

socket = myapp.sock
chmod-socket = 660
vacuum = true

die-on-term = true

Save and close the file.

Here, module specifies the module that provides an entry point for the Django application.

To allow Nginx to handle requests, you specify a socket called myapp.sock which will be used by Nginx to serve requests.

To set the proper permissions, you use the chmod-socket option. Setting vacuum to true cleans up the socket once the process stops.

Automatically Start uWSGI on Boot

Now that the application and uWSGI are ready, create a systemd service unit file to automatically start uWSGI and serve the Django application at boot.

First, make sure to deactivate the virtual environment in your mysite directory:

deactivate

Create a myapp.service file inside the /etc/systemd/system directory:

sudo nano /etc/systemd/system/myapp.service

Add the following to it:

[Unit]
Description=uWSGI instance to serve myapp
After=network.target

[Service]
User=your_user
Group=www-data
WorkingDirectory=/home/your_user/myapp/mysite
Environment="PATH=/home/your_user/myapp/env/bin"
ExecStart=/home/your_user/myapp/env/bin/uwsgi --ini myapp.ini

[Install]
WantedBy=multi-user.target

Save and close the file.

The After=network.target line tells systemd to start this service after the network starts.

In the [Service] block, you specify the user and group that will run this service, replace your_user with the user who owns the files of the Django application. You give group ownership to the www-data group to allow Nginx to access and communicate with uWSGI.

You set WorkingDirectory to the full path of the application's project folder, and you specify your python environment's bin directory with Environment.

The ExecStart runs uWSGI with the myapp.ini configuration file you created earlier.

In the WantedBy=multi-user.target line, you tell systemd to start this service when the regular multi-user system is started.

Note: Systemd requires the full path to the uWSGI executable, which is installed within your virtual environment inside the bin directory. Remember to replace the username and the paths with your own.

You can now start your myapp.service you just created and enable it to start at boot:

sudo systemctl start myapp.service
sudo systemctl enable myapp.service

Check the status:

sudo systemctl status myapp

You should receive the following output indicating that your myapp.service is active and running:

● myapp.service - uWSGI instance to serve myapp
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2022-11-27 11:06:54 UTC; 24min ago
   Main PID: 43538 (uwsgi)
      Tasks: 6 (limit: 19068)
     Memory: 42.3M
        CPU: 680ms
     CGroup: /system.slice/myapp.service
             ├─43538 /home/abd/myapp/env/bin/uwsgi --ini myapp.ini
             ├─43539 /home/abd/myapp/env/bin/uwsgi --ini myapp.ini
             ├─43540 /home/abd/myapp/env/bin/uwsgi --ini myapp.ini
             ├─43541 /home/abd/myapp/env/bin/uwsgi --ini myapp.ini
             ├─43542 /home/abd/myapp/env/bin/uwsgi --ini myapp.ini
             └─43543 /home/abd/myapp/env/bin/uwsgi --ini myapp.ini

Configuring Nginx as a Reverse Proxy

Now that uWSGI is running and serving your Django application, you can configure Nginx to pass web requests to it.

Create a new server block configuration file called myapp in your Nginx’s sites-available directory:

sudo nano /etc/nginx/sites-available/myapp

Add the following configuration to this new server block:

server {
    listen 8000;
    server_name 107.155.122.24;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/your_user/myapp/mysite/myapp.sock;
    }
}

Save and close the file.

Here, you tell Nginx to listen on port 8000 and specify your IP address or domain name. Then in the location block, you include the proxy_params file for proxying, and then you use the proxy_pass directive to pass web requests to the socket you created earlier in myapp.service. Remember to change your_user to your username.

Link this new Nginx configuration to the sites-enabled directory:

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled

Unlink Nginx's default configuration file:

sudo unlink /etc/nginx/sites-enabled/default

Test the configuration for errors:

sudo nginx -t

You should receive an output that informs you that the test is successful.

Restart Nginx:

sudo systemctl restart nginx

If you haven't already, give Nginx full access in ufw:

sudo ufw allow 'Nginx Full'

Next, make sure that Nginx can access the uWSGI socket file by giving your home directory 0755 permissions:

sudo chmod 755 /home/your_user

With this, navigate to your website with your browser:

http://your_server_ip_or_domain:8000

And you should see that your Django application was successfully served.

Congrats

You have learned how to create a Django application and serve it using uWSGI and Nginx. To learn more about Django, check out the official documentation.

A note about tutorials: We encourage our users to try out tutorials, but they aren't fully supported by our team—we can't always provide support when things go wrong. Be sure to check which OS and version it was tested with before you proceed.

If you want a fully managed experience, with dedicated support for any application you might want to run, contact us for more information.

Leave a Reply