Skip to main content

Django Deployment with Nginx in Ubuntu

00:03:19:73

Install the Packages from the Ubuntu Repositories first. If you are using Django with Python 3, type:

shell
sudo apt-get update
sudo apt-get install python3-pip python3-dev libpq-dev nginx

Postgresql installation

shell
sudo apt-get update
sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx

MySQL installation

shell
sudo apt-get update
sudo apt-get install mysql-server
mysql_secure_installation

Database creation

sql
CREATE DATABASE myproject;
  1. Postgres
sql
CREATE USER myprojectuser WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
  1. MySQL
sql
CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON * . * TO 'newuser'@'localhost';

Python VirtualEnv Creation

shell
sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenv
cd ~/myproject
virtualenv myprojectenv
source myprojectenv/bin/activate
pip install django gunicorn psycopg2 (For Postgres)

Changes in setting.py

python
ALLOWED_HOSTS = [*]
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
    }
}

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
    }
}

Migrations

Now, we can migrate the initial database schema to our database using the management script:

shell
python manage.py makemigrations
python manage.py migrate

Create an administrative user for the project by typing:

shell
python manage.py createsuperuser

You will have to select a username, provide an email address, and choose and confirm a password. We can collect all of the static content into the directory location we configured by typing:

shell
python manage.py collectstatic

Create a Gunicorn systemd Service File

Now, we are going to implement a more robust way of starting and stopping the application server with Gunicorn. To accomplish this, we’ll make a systemd service file.

Create and open a systemd service file for Gunicorn with sudo privileges in your text editor:

shell
sudo nano /etc/systemd/system/gunicorn.service

gunicorn.service file

shell
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
Type=notify
# the specific user that our service will run as
User=root
Group=root
# another option for an even more restricted service is
# DynamicUser=yes
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
RuntimeDirectory=gunicorn
WorkingDirectory=/var/www/html/[ProjectName]
ExecStart=/var/www/html/[ProjectName]/project_venv/bin/gunicorn config.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Check for the Gunicorn Socket File

Check the status of the process to find out whether it was able to start:

shell
sudo systemctl status gunicorn

Create gunicorn.socket

shell
sudo nano /etc/systemd/system/gunicorn.socket

gunicorn.socket File

shell
[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock
# Our service won't need permissions for the socket, since it
# inherits the file descriptor by socket activation
# only the nginx daemon will need access to the socket
User=www-data
# Optionally restrict the socket permissions even more.
# Mode=600

[Install]
WantedBy=sockets.target

Run gunicorn service

shell
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
sudo systemctl status gunicorn
sudo systemctl daemon-reload
sudo systemctl restart gunicorn

Configure Nginx to Proxy Pass to Gunicorn

shell
sudo nano /etc/nginx/sites-available/[ProjectName]

Then, type

shell
upstream app_server {
    server unix:/run/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;
    listen [::]:80;
    server_name 128.199.221.253;  # here can also be the IP address of the server

    keepalive_timeout 5;
    client_max_body_size 4G;

    access_log /var/www/html/[ProjectName]/logs/nginx-access.log;
    error_log /var/www/html/[ProjectName]/logs/nginx-error.log;

    location /static/ {
        autoindex on;
        alias /var/www/html/[ProjectName]/static/;
    }

    # checks for static file, if not found proxy to app
    location / {
        try_files $uri @proxy_to_app;
      }

    location @proxy_to_app {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app_server;
    }
  }

Adding SSL Certificate

upstream app_server {
    server unix:/run/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;
    listen [::]:80;
    server_name 128.199.79.246;  # here can also be the IP address of the server
    return 301 https://[DomainName]$request_uri;
  }

server{
    # SSL configuration
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name [DomainName];

    ssl        on;
    ssl_certificate         /etc/ssl/certs/cert.pem;
    ssl_certificate_key     /etc/ssl/private/key.pem;
    ssl_client_certificate /etc/ssl/certs/cloudflare.crt;
    ssl_verify_client on;

    keepalive_timeout 5;
    client_max_body_size 4G;

    access_log /home/[UserName]/logs/nginx-access.log;
    error_log /home/[UserName]/logs/nginx-error.log;

    location /static/ {
        autoindex on;
        alias /home/[UserName]/[ProjectName]/[DjangoAppName]/static/;
    }

    # checks for static file, if not found proxy to app
    location / {
        try_files $uri @proxy_to_app;
      }

    location @proxy_to_app {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app_server;
    }
}

Restart all the service

shell
sudo systemctl daemon-reload
sudo systemctl restart gunicorn
sudo nginx -t && sudo systemctl restart nginx