Django Deployment with Nginx in Ubuntu
Tags: django, nginx, tutorial
Published: 2022-06-25 08:03:51

> 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:

```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;
```
2.	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
```