DEV Community

Hein Khant Zaw
Hein Khant Zaw

Posted on

Django Deployment with Nginx in Ubuntu

This was just a note for myself as I faced several errors during my first deployment with Django. This note is for those who are facing problems during the deployment. I hope it helps!

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

sudo apt-get update
sudo apt-get install python3-pip python3-dev libpq-dev nginx
Enter fullscreen mode Exit fullscreen mode

Postgresql installation

sudo apt-get update
sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx 
Enter fullscreen mode Exit fullscreen mode

MySQL installation

sudo apt-get update
sudo apt-get install mysql-server
mysql_secure_installation
Enter fullscreen mode Exit fullscreen mode

Database creation

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

Python VirtualEnv Creation

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)
Enter fullscreen mode Exit fullscreen mode

Changes in setting.py

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',
    }
}
Enter fullscreen mode Exit fullscreen mode

Migrations

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

python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Create an administrative user for the project by typing:

python manage.py createsuperuser
Enter fullscreen mode Exit fullscreen mode

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:

python manage.py collectstatic
Enter fullscreen mode Exit fullscreen mode

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:

sudo nano /etc/systemd/system/gunicorn.service
Enter fullscreen mode Exit fullscreen mode

gunicorn.service file

[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
Enter fullscreen mode Exit fullscreen mode

Check for the Gunicorn Socket File

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

sudo systemctl status gunicorn
Enter fullscreen mode Exit fullscreen mode

Create gunicorn.socket

sudo nano /etc/systemd/system/gunicorn.socket
Enter fullscreen mode Exit fullscreen mode

gunicorn.socket File

[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
Enter fullscreen mode Exit fullscreen mode

Run gunicorn service

sudo systemctl start gunicorn
sudo systemctl enable gunicorn
sudo systemctl status gunicorn
sudo systemctl daemon-reload
sudo systemctl restart gunicorn
Enter fullscreen mode Exit fullscreen mode

Configure Nginx to Proxy Pass to Gunicorn

sudo nano /etc/nginx/sites-available/[ProjectName]
Enter fullscreen mode Exit fullscreen mode

Then, type

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;
    }
  }
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

Restart all the service

sudo systemctl daemon-reload
sudo systemctl restart gunicorn
sudo nginx -t && sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

Top comments (0)