Documentation for Deployment of Applications and Managing with Supervisor
Published: 2024-01-24 11:35:08

#### This involves deployment and integration of Django app, Postgres, Gunicorn, Nginx and Supervisor(used for managing gunicorn instances)



## Copy the Django application from LOCAL to REMOTE server

Run this command on local system

```console
scp -r <path-to-django-app-on-local>  ubuntu@<ip address>:<path-where-you-want-to-copy-to-on-remote>
```

## Log into Remote Server  and install libraries from UBUNTU Repositories
```
sudo apt update
sudo apt install python3-venv python3-dev libpq-dev postgresql postgresql-contrib nginx curl
```

## Setting up PostgreSQL DB and User

Log into postgres session
```console
sudo -u postgres psql
```

Inside Postgres Prompt setting up DB and user
```console
CREATE DATABASE <db-name>;

CREATE USER <username> WITH PASSWORD '<password>';

ALTER ROLE <username> SET client_encoding TO 'utf8';

ALTER ROLE <username> SET default_transaction_isolation TO 'read committed';

ALTER ROLE <username> SET timezone TO 'UTC';

GRANT ALL PRIVILEGES ON DATABASE <db_name> TO <username>;
```

## Setting up Django-Project and Virtual Environment

Create Virtual Environment for Django Project and activate
```console
python3 -m venv <environment-name>

source <environment-name>/bin/activate
```

Install psycopg for postgres support 
```console
 pip install psycopg2-binary
```

Install gunicorn
```console
pip install gunicorn
```

## Now Integrating PostgreSQL

Go to Configs and change the database values to following

```
DATABASES = {
				    'default': {
				        'ENGINE': 'django.db.backends.postgresql_psycopg2',
				        'NAME': 'db-name',
				        'USER': 'username',
				        'PASSWORD': 'password',
				        'HOST': 'localhost',
				        'PORT': '',
				    }
			}
```
Making exception for port 8000
```
sudo ufw allow 8000
```

Run following commands to check integrity and collect static
```console
python manage.py makemigrations

python manage.py migrate
		
python manage.py runserver

python manage.py collectstatic
```
## SETTING UP GUNICORN FOR SUPERVISOR (IF NOT SETUP)

Create a gunicorn file managed by supervisor inside bin folder of virtual env

```console
cd <path to env of django app>/bin

sudo nano gunicorn_supervisor
```

PASTE the following bash script configuration to run Gunicorn and make changes for individual sock files, path to project, user/group etc accordingly.


```console
#!/bin/bash


DIR=<path to django app directory where manage.py is present>  #Directory where project is located
USER=ubuntu   #User to run this script as
GROUP=ubuntu  #Group to run this script as
WORKERS=3     #Number of workers that Gunicorn should spawn
SOCKFILE=unix:/run/<project-name>.sock  #This socket file will communicate with Nginx 
DJANGO_SETTINGS_MODULE=<project-dir-name-which-contains-settings.py>.settings   #Which Django setting file should use
DJANGO_WSGI_MODULE=<project-dir-name-which-contains-wsgi.py>.wsgi           #Which WSGI file should use
LOG_LEVEL=debug
cd $DIR
source <path to venv>/bin/activate  #Activate the virtual environment
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DIR:$PYTHONPATH


#Command to run the progam under supervisor
exec <path-to-venv>/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
--workers $WORKERS \
--user=$USER \
--group=$GROUP \
--bind=$SOCKFILE \
--pythonpath <path-to-venv>/bin/python \
--log-level=$LOG_LEVEL \
--access-logfile=/var/log/supervisor/<name-the-file>.log \
--error-logfile=/var/log/supervisor/<name-the-file>.log

```

Give Permissions for this file to read-write-execute
```
sudo chmod 755 gunicorn_supervisor
```

## Creating Supervisor program for managing the Gunicorn Instances

```
sudo apt-get install supervisor
```

Creating a conf file for supervisor to watch for Gunicorn Instance of the django app

```
cd /etc/supervisor/conf.d/

sudo nano <app-name>.conf
```

Paste the following and make changes accordingly for user, logs and program name

```
[program:<program-name>]
command=<path-to-app-venv>/bin/gunicorn_supervisor
user=root
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/<name-of-error-log-file>.log
stdout_logfile=/var/log/supervisor/<name-of-output-log-file>.log

```

Run the following commands

```
sudo supervisorctl reread
sudo supervisorctl update
```
You can also check the status of your app or start, stop or restart it using supervisor.

```
sudo supervisorctl status <program-name>
sudo supervisorctl start <program-name>
sudo supervisorctl stop <program-name>
sudo supervisorctl restart <program-name>
```

## NGINX Installation and Setup

Creating configuration for Nginx to proxy pass Gunicorn 

```
sudo nano /etc/nginx/sites-available/<project-name>
```

Now Paste this and make changes accordingly linking correct sock file 

```
server {
    listen 80;
    server_name server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root <path-to-dir-which-contains-static-dir>;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/<name-of-sock-file>;
    }
}
```

If there are multiple applications being served from same domain/IP then:-

    1. Make individual app files within nginx
    2. Change listening port of server i.e every app will listen on individual ports

        eg:- app1                               app2

            server {                            server {
                listen 80;                          listen 81;
                ....                                ....
            }                                   }



```
sudo ln -s /etc/nginx/sites-available/<project-name> /etc/nginx/sites-enabled
```

To save the configs and check for any errors

```
sudo nginx -t
```

Restart Nginx
```
sudo systemctl restart nginx
```

Finally, you need to open up your firewall to normal traffic on port 80. Since you no longer need access to the development server, you can remove the rule to open port 8000

```
sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'
```

## Troubleshooting Nginx, Gunicorn and Supervisor