Deploy a python django and reactJS restful app with gunicorn, supervisor and nginx on a linux ubuntu server.
Tags: django, react, restful, ubuntu
Published: 2022-07-05 13:11:25

The task is to deploy a decoupled Application with 2 seperate services that communicate with each other using API. The frontend app written with ReactJS - a popular Javascript library - and a backend app that handles the database written in Python using the Django restframework library.  The 2 apps are also hosted on the github server repository.
The React app communicates with the Django/ Server over REST HTTP methods such as POST, GET, PUT, PATCH, DELETE etc.

**Step 1: staging the apps on the server**
- Git clone your django app on the Ubuntu server e.g. `$ git clone https://github.com/<your username>/<your git repo>`
- Git clone your reactJS app too.
You should have 2 folders listed on the server with all the files.

**Step 2: Manual compile and prepare the reactJS frontend.**
- `$ cd` into your reactJS frontend folder by typing. `cd <frontend folder name>`
- `$ yarn install` or `$ npm install` to add dependencies and packages to your app. if `yarn` or `node` is not installed on the ubuntu server, make sure you install these libraries first. 
- `$ yarn run build` to transpile the final static and bundled files.
- Your frontend app will now include a `build` folder with the static and bundled files.

**Step 3:  Staging and Preparing the Django a**pp
- Create a new virtual environment for the django app by running `python3 m venv <virtual env name>`
- Activate the virtual environment by running: `source <virtual env name>/bin/activate`
- Install all dependencies for the django app by running: `pip install -r requirements.txt`
- Install Gunicorn if not already installed by running: `pip install gunicorn`

**Step 4: Create a Gunicorn shell script to execute the django app**
- Change user to root by logging as root user.
- Create a gunicorn shell script preferably in the same folder as the django app e.g. gunicorn.sh.
- An example draft template of this gunicorn script should look like this:

```
#!/bin/bash
NAME="<service name>" #name of the service to be run by supervisor
DJANGODIR=<path/to/django app>
USER=<user e.g. root> #you can see your user name by running command whoami
GROUP=<usergroup e.g. root>
NUM_WORKERS=<number of workers e.g. 2>
TIMEOUT=<e.g 500>
DJANGO_SETTINGS_MODULE=<app.settings<the django settings file>>
DJANGO_WSGI_MODULE=<app.wsgi< the wsgi file>>
PORT=<8500>
LOCAL_IP=<127.0.0.1>

echo "Starting $NAME as `whoami`"

cd $DJANGODIR
source <path/to/virtualenv/bin/activate> #run the virtual environment
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE #set the global variable to the settings file
export PYTHONPATH=$DJANGODIR:$PYTHONPATH #set your django app directory as python path

exec <path/to/virtualenv/bin/gunicorn ${DJANGO_WSGI_MODULE} >
--name $NAME \
--workers $NUM_WORKERS \
--timeout $TIMEOUT \
--user=$USER --group=$GROUP \
--pythonpath=<path/to/virtualenv/bin \
--log-level=debug \
--bind=$LOCAL_IP:PORT \
--logo-file=-
```

- Run the gunicorn shell script by executing `./gunicorn.sh` 

**Step 5: Configure the Supervisor**
- Supervisor in this case scenario is responsible for running the django service. Before you proceed, make sure the `supervisor` library /package is correctly installed on the Ubuntu VPS.
- check the current service list by running `$ sudo supervisorctl status` 
This will display a list of service names available.
- Add a New Service as set in the `gunicorn.sh` script above by navigating to `$ cd /etc/supervisor/conf.d`. Then create your service conf file e.g `sudo nano <name.conf>`
- To update the supervisor list. Run `supervisorctl reread`. This command will make your configuration changes available.


**Step 6: Add Nginx to serve the applications**
- Nginx will serve both our applications on the default port 80. Make sure the nginx library or package is installed on the Ubuntu machine.
- Navigate to the nginx folders as: `$ cd /etc/nginx/sites-available` and create a new conf file for your application configuration.
- Create a conf file as `<sudo nano name.conf>`
- Add a server block as shown below:

```
server {

        server_name <name/your preferred domain name>;

        proxy_read_timeout 300;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;


        location / {
            root /path/to/react/frontend/build;
        }
        location /api/v1 {
            proxy_pass http://<localhost>:<port name configured in gunicorn shell script >;
        }
}
```

- The server block above shows includes 2 location directives. 
- The root folder <server name> directive serves the reactjs build folder that includes the index.html file.
- The location directive `<server name/ap1/v1>` will serve the django rest server using a proxy pass address.


### Happy Coding!