Overview

In this guide, I will demonstrate how to install and configure some components on Ubuntu to support and serve Django applications.

We will configure the Gunicorn application server to interface with our applications.

We will then set up Nginx to reverse proxy to Gunicorn, giving us access to its security and performance features to serve our apps.

Prerequisites

  • You have an ubuntu server with sudo privileges
  • You already have you django application running, if not you can check out my Django setup article

Installation

First we will install required packages and libraries

# Python3 Installation

sudo apt-get update
sudo apt-get install python3
sudo apt install python3-pip

sudo apt-get install python3-dev libmysqlclient-dev
sudo apt-get install build-essential
# [OPTIONAL]
# Virtual environment installation

sudo apt-get install virtualenv

# Create a virtual environment
virtualenv -p python3 venv
# Nginx Installation

sudo apt update
sudo apt install nginx
# Gunicorn Installation

pip install gunicorn

Setting Up Django

We need to configure settings.py and main urls.py

# settings.py

# You can set your own path or you can do the same

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
STATIC_ROOT = os.path.join(BASE_DIR,"static_root")

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,"media_root")

NOTE: Your project will probably also have static assets that aren’t tied to a particular app. In addition to using a static/ directory inside your apps, you can define a list of directories (STATICFILES_DIRS) in your settings file where Django will also look for static files. 

 
# urls.py

from django.conf import settings
from django.conf.urls.static import static

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

If your debug=False, then run command to collect all staticfiles to your static root:

python manage.py collectstatic

Finally test your project, by running:

python manage.py runserver 0.0.0.0:8000

# [OPTIONAL]
# If you are facing any problem related to port or firewall which might have blocked your port.
# you can look into this article on UFW firewall
# https://raturi.in/blog/how-set-firewall-ufw-ubuntu-debian/

# Make sure after following the above article you have your ssh service running.
# By default when ufw is enabled it block ssh, means you cannot log in to server. 
# Do not close your terminal and start your ssh service by running:

sudo service ssh start or sudo service ssh restart
sudo ufw allow OpenSSH or sudo ufw allow 22

# If you have your ssh port something else then mention your port number
# sudo ufw allow <portnumber>

Testing Gunicorn’s Ability to Serve the Project

gunicorn --bind 0.0.0.0:8000 yourproject.wsgi:application

Note: Change yourproject above to the name of your project folder where wsgi.py is located, basically its in the same folder where settings.py is located.This will start Gunicorn on the same interface that the Django development server was running on. You can go back and test the app again.

We passed Gunicorn a module by specifying the relative directory path to Django’s wsgi.py file, which is the entry point to our application, using Python's module syntax. Inside of this file, a function called application is defined, which is used to communicate with the application.

Creating Gunicorn service file

Open file in: /etc/systemd/system/gunicorn.service and paste the following:

[Unit] 
Description=gunicorn daemon 
After=network.target 

[Service] 
User=ubuntu 
Group=www-data 
WorkingDirectory=/path/to/yourproject-directory 
ExecStart=path/to/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/path/to/project/project.sock yourproject.wsgi:application 

[Install] 
WantedBy=multi-user.target

NoteReplace WorkinDirectory , ExecStart path to your path

Now save and close the file

To load your service file run:

sudo systemctl daemon-reload

Now start your service by:

sudo service gunicorn start

For now a socket file should have created at your specified WorkinDirectory path: /path/to/project/project.sock if not, verify the process again and then proceed further

To check gunicorn status; you can run:

sudo service gunicorn status

Configure Nginx to Proxy Pass to Gunicorn

Now that Gunicorn is set up, we need to configure Nginx to pass traffic to the process.

Start by creating and opening a new server block in Nginx’s sites-available directory:

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

Inside, open up a new server block. We will start by specifying that this block should listen on the normal port 80 and that it should respond to our server’s domain name or IP address:

Next, we will tell Nginx to ignore any problems with finding a favicon. We will also tell it where to find the static assets that we collected in our ~/myproject/static directory. All of these files have a standard URI prefix of "/static", so we can create a location block to match those requests:

Finally, we’ll create a location / {} block to match all other requests. Inside of this location, we'll include the standard proxy_params file included with the Nginx installation and then we will pass the traffic to the socket that our Gunicorn process created:

server { 
listen 80; 
server_name server_domain_or_IP; 
location = /favicon.ico { 
access_log off; log_not_found off; 
} 
location /static { 
alias /your-static-root-path/; 
}
location /media { 
alias /your-media-root-path/; 
}  
location / { 
include proxy_params; 
proxy_pass http://unix:/your/socket-file-path/yourproject.sock; 
} 
}

NoteChange server_name server_domain_or_IP to your domain or ip. For example: example.com or 192.168.1.0

Note:Change alias /your-static-root-path/ to your static_root path. For example alias /home/nitin/project/static_root/

Note:Change alias /your-media-root-path/ to your media_root path. For example alias /home/nitin/project/media_root/

Notechange proxy_pass http://unix:/your/socket-file-path/yourproject.sockto your .sockfile 

Save and close the file when you are finished.

Now, we can enable the file by linking it to the sites-enabled directory:

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

Test your Nginx configuration for syntax errors by typing:

sudo nginx -t

If no errors are reported, go ahead and restart Nginx by typing:

sudo service nginx restart

You should now be able to go to your server’s domain or IP address to view your application.