If you are looking to deploy a Django project with Nginx and Gunicorn, first you need to understand the basics.
Django is an open-source web application framework that lets you build complex websites and web services quickly and efficiently. You write Django in Python, meaning that if you’ve got some knowledge of this programming language, you can start using it almost immediately.
Nginx and Gunicorn are two popular open-source web servers. In this guide, I’ll teach you how to install and use Nginx and Gunicorn on Ubuntu 22.04 LTS, the latest version of Ubuntu at the time of writing. This guide is beginners friendly. We’ll be making a new virtualenv to create a clean project environment. Then, I’m going to show you how we can deploy a Django project with Nginx and Gunicorn.
Installation and Virtual Environment
Let’s start by connecting to our Ubuntu server and updating the current packages installed on the server.
sudo apt update
Next, we will download and install Nginx, Pip, VirtualEnv and curl from Ubuntu Repositories. We will download the remaining packages from Python Package Index (PyPI).
sudo apt install nginx python3-pip python3-virtualenv curl
Before cloning the Django project from Github, we will create a folder called nginx-django, a new virtual environment, and activate the new virtual environment. Let’s create and switch to the new folder.
mkdir nginx-django cd nginx-django
The new folder will contain the cloned Django project and the new virtual environment. Let’s create and activate the virtual environment.
virtualenv env source env/bin/activate
Cloning From GitHub
Now that the virtual environment is ready, we can clone the project from Github.
git clone https://github.com/isaiaholadapo/nginx-tutorial.git
The project is cloned into a folder called nginx-tutorial, so let’s switch to this folder and install the project requirements.
cd nginx-tutorial pip install -r requirements.txt
To access the project from our PC, we need to edit the project settings.py file and allow external connections to the project. Let’s locate line 28, which contains the ALLOWED_HOSTS = []
. In the square bracket, we can add all the domains or IPs that will have access. If we want to open it to everyone, we can use an asterisk. For this tutorial, we will use an asterisk.
nano nginxtutorial/settings.py
The command above will open the vim editor. Scroll down till you locate the ALLOWED_HOSTS = []
and change it to ALLOWED_HOSTS = ['*']
. Press control + o
to save changes and control + x
to exist.
We will need to run the migration, collect static and create a super user using the code snippets below.
python manage.py migrate python manage.py collectstatic python manage.py createsuperuser
This is the last phase of our project setup. We will run the project server before running the server and confirm that port 8000 is on your hosting server. We will use 0.0.0.0
as the host so that we can access the project from your server IP.
python manage.py runserver 0.0.0.0:8000
From your PC server type the snippet below to access the project.
http://your_server_public_ip:8000
The Django default project page should show on your browser. Press `control + c` to stop the server from running.
Gunicorn
Gunicorn will serve the project. It will allow the project to run without using Django python manage.py runserver
command. Let’s install it using pip.
pip install gunicorn
Let’s serve the project using Gunicorn.
gunicorn --bind 0.0.0.0:8000 nginxtutorial.wsgi
Confirm that the application is running from your browser using the URL below:
http://your_server_public_ip:8000
Let’s stop the Gunicorn using control + c
and deactivate the virtual environment before moving to the next step.
deactivate
Socket File
To improve how the project server is started and stopped, we’ll create a systemd socket file that will listen for incoming connections so that Gunicorn will handle the connection. Let’s create a socket file using sudo.
sudo nano /etc/systemd/system/nginxtutorial.socket
This will open a text editor. Paste the code snippet below:
[Unit] Description=nginxtutorial socket [Socket] ListenStream=/run/nginxtutorial.sock [Install] WantedBy=sockets.target
In the code snippet above, the unit section describes the socket, while the socket section contains the sock file location and the install section ensures that the file is created.
Next, we will create the nginxtutorial.service
file using sudo.
sudo nano /etc/systemd/system/nginxtutorial.service
In the text editor window, paste the code snippet below:
[Unit] Description=nginxtutorial daemon Requires=nginxtutorial.socket After=network.target [Service] User=ubuntu Group=www-data WorkingDirectory=/home/ubuntu/nginx-django/nginx-tutorial ExecStart=/home/ubuntu/nginx-django/env/bin/gunicorn \ --access-logfile - \ --workers 3 \ --bind unix:/run/nginxtutorial.sock \ nginxtutorial.wsgi:application [Install] WantedBy=multi-user.target
We have successfully created the service file. Confirm that the WorkingDirectory and ExecStart path is your project path. Let’s start, enable and check the status of the socket file.
sudo systemctl start nginxtutorial.socket sudo systemctl enable nginxtutorial.socket sudo systemctl status nginxtutorial.socket
You should get a message that tells you it’s active and listening. If you receive any error message, you can check the socket log using:
sudo journalctl -u nginxtutorial.socket
Let’s confirm the sock file using the code snippet below.
file /run/nginxtutorial.sock
The nginxtutorial.service
file is not yet active because no connection has been received yet. When you check the status using the code snippet below, its status will be nginxtutorial.service
.
sudo systemctl status nginxtutorial
Activating the Service File
Let’s activate it by sending a connection using curl
.
curl --unix-socket /run/nginxtutorial.sock localhost
An HTML output will be returned. This means that Gunicorn has been started, and it can serve the project. If you didn’t get the HTML output, check its logs using:
sudo journalctl -u nginxtutorial
Also, check that the service file /etc/systemd/system/nginxtutorial.service
is properly configured. If you edit the file, you will need to reload the daemon and restart the Gunicorn.
sudo systemctl daemon-reload sudo systemctl restart nginxtutorial
You can confirm its status using:
sudo systemctl status nginxtutorial
Nginx
Let’s configure Nginx by creating a server block in the sites-available directory.
sudo nano /etc/nginx/sites-available/nginxtutorial
Inside the text editor, let’s type the code snippet below:
server { listen 80; server_name your_server_domain_or_IP; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/ubuntu/nginx-django/nginx-tutorial; } location / { include proxy_params; proxy_pass http://unix:/run/nginxtutorial.sock; } }
Note: Ensure to replace the server_domain_or_IP with your domain or server IP. The root should contain your project directory path.
Let’s link it to the `sites-enabled` directory using:
sudo ln -s /etc/nginx/sites-available/nginxtutorial /etc/nginx/sites-enabled
Let’s test the configuration so that we can be sure that everything is working correctly.
sudo nginx -t
If you get a success message, you will need to restart nginx using:
sudo systemctl restart nginx
But if you get an error message, check your configuration in sudo nano /etc/nginx/sites-available/nginxtutorial
and you can also check the error logs using:
sudo tail -F /var/log/nginx/error.log
You can access your project using your server IP or domain. If you want to use your domain, ensure that the domain is linked to your server.
Troubleshooting
If your CSS and JavaScript files are not loaded, you can edit the nginx.conf
file and change the www-data
to your server username e.g. ubuntu
.
sudo nano /etc/nginx/nginx.conf
Whenever you edit your project code, you will need to restart the Gunicorn process so that the changes can reflect on your website.
sudo systemctl restart nginxtutorial
If you edit the socket or service files, you need to reload the daemon, and the process restarts.
sudo systemctl daemon-reload sudo systemctl restart nginxtutorial.socket nginxtutorial.service
Whenever the Nginx server block is edited:
sudo nginx -t && sudo systemctl restart nginx
If you want to view Nginx error logs:
sudo less /var/log/nginx/error.log
Conclusion
We started by preparing our virtual environment and installing the virtualenv package via pip. We then created a virtual environment in the directory where the Django project was and activated it. The next step was to get our Django project ready to be served by Gunicorn and Nginx. Finally, we configured Gunicorn to get it ready to serve requests from Nginx and then configured Nginx using Gunicorn as a proxy to make all of this work.
If you are curious about what else you can do with Django, take a look at this article on using the Django REST framework to serialize data