Introduction
Django is a web framework that allows you to create web applications using the Python language. Gunicorn 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 Gunicorn, and configure Nginx as a reverse proxy that sits in front of Gunicorn 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 asudo
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 Gunicorn, 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 Gunicorn:
pip install django gunicorn
With Django and Gunicorn 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 Gunicorn
Now that you've set up your sample Django application, you can set up Gunicorn.
Inside your mysite
project, activate the environment if you haven't already.
Run the application with Gunicorn by giving it the 0.0.0.0:8000
interface and the project's WSGI module.
gunicorn --bind 0.0.0.0:8000 mysite.wsgi
You should see output like the following:
[2022-11-20 16:49:59 +0100] [6994] [INFO] Starting gunicorn 20.1.0
[2022-11-20 16:49:59 +0100] [6994] [INFO] Listening at: http://0.0.0.0:8000 (6994)
[2022-11-20 16:49:59 +0100] [6994] [INFO] Using worker: sync
[2022-11-20 16:49:59 +0100] [6995] [INFO] Booting worker with pid: 6995
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 Gunicorn server is functioning correctly.
Automatically Start Gunicorn on Boot
Now that the application and Gunicorn are ready, create a systemd service unit file to automatically start Gunicorn 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=Gunicorn 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/gunicorn \
--workers 3\
--bind unix:mysite.sock -m 007\
mysite.wsgi:application
[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 Gunicorn.
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 Gunicorn with 3 workers (adjust this as you see fit), and creates a mysite.sock
socket file. You also pass in the Django project name and the WSGI module (mysite.wsgi
).
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 Gunicorn 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 - Gunicorn instance to serve myapp
Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2022-11-18 14:17:31 UTC; 7s ago
Main PID: 59209 (gunicorn)
Tasks: 4 (limit: 19072)
Memory: 55.5M
CPU: 821ms
CGroup: /system.slice/myapp.service
├─59209 /home/abd/myapp/env/bin/python3 /home/abd/myapp/env/bin/gunicorn --work>
├─59210 /home/abd/myapp/env/bin/python3 /home/abd/myapp/env/bin/gunicorn --work>
├─59211 /home/abd/myapp/env/bin/python3 /home/abd/myapp/env/bin/gunicorn --work>
└─59212 /home/abd/myapp/env/bin/python3 /home/abd/myapp/env/bin/gunicorn --work>
Configuring Nginx as a Reverse Proxy
Now that Gunicorn 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 8080;
server_name your_IP_or_domain;
location / {
include proxy_params;
proxy_pass http://unix:/home/your_user/myapp/myapp.sock;
}
}
Save and close the file.
Here, you tell Nginx to listen on port 8080
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 Gunicorn 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:8080
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 Gunicorn 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.