In this tutorial, you will learn how to deploy a Django application with PostgreSQL, Nginx, Gunicorn on a Red Hat Enterprise Linux (RHEL) version 7.3. For testing purpose I’m using an Amazon EC2 instance running RHEL 7.3.
Recently I had to deploy an existing Django project running on Ubuntu 16.04 to a new environment, RHEL 7.3. It gave me some headache because I don’t have much server administration skills and I wasn’t familiar with Security Enhanced Linux (SELinux) distributions, so I thought about sharing the details of the deployment so it could help someone in the same position I was.
If you are just getting started with Django deployment, and doesn’t have a good reason to be using RHEL, I suggest you use Ubuntu instead. It requires less configuration, and the process is fairly easier than using RHEL. Perhaps you could check this past tutorial: How to Deploy a Django Application to Digital Ocean.
Anyway, for this tutorial I will deploy the following Django application:
github.com/sibtc/urban-train. It is just an empty Django project to demonstrate
the deployment process. So, every time you see urban-train
, change it for your project name.
Initial Setup
First, let’s install all the needed resources and applications. Get started by installing git
, gcc
and
python-virtualenv
. Everything should be available in the yum repository.
Create a system user for the application:
Create the Django project home inside /opt
:
Give the permissions to the urbantrain
user:
PostgreSQL Server
Now install PostgreSQL 9.6
server and development tools:
Initialize the database:
Start and enable the PostgreSQL 9.6
service:
Log in with the postgres
user:
Create a database user, set a password (save it for later) and create a database for the Bootcamp application:
Now we have to update the authentication method of the database user in the file pg_hba.conf
:
Go to the bottom of the file, find this snippet:
Change the method from ident
to md5
on the IPv4
and IPv6
rows:
Save the file and exit.
Now, log out from the postgres session:
Restart the PostgreSQL 9.6
server:
Python Virtual Environment
First, log in with the urbantrain
system user:
Start a new python-virtualenv
inside the /opt/urban-train
directory:
Activate the python-virtualenv
:
Create a directory named logs
that will be used by Gunicorn
and Nginx
to write the logs:
Clone your project’s repository inside the /opt/urban-train
directory:
Now we have to install the Python dependencies. But first, add the PostgreSQL
to the path. The psycopg2
will need
it to install:
Upgrade the Python package manager:
Install the dependencies (/opt/urban-train/urban-train/requirements.txt
inside the repository):
Migrate the database:
Collect the static assets (css, javascripts, images, etc.):
Gunicorn
Still logged in with the urbantrain
user, let’s create a gunicorn_start
file to startup the application server.
Use the structure below, change the paths, user/groups etc accordingly to your environment/project:
Make the gunicorn_start
file executable:
Create a directory named run, for the unix socket file:
Gunicorn Systemd Service
Now let’s create a systemd service file for gunicorn
server to manage
First, exit the urbantrain
user. Create the following systemd service file:
Insert the following in the file:
Start the gunicorn
systemd service we created and enable it so that it starts at boot:
Nginx
The application must be served behind a proxy server. First, create a yum repo file:
Add repository information:
Save and exit.
Now install nginx
:
Because of the security policies of the SELinux, we need to manually add the httpd_t
to the list of permissive
domains, run this command:
Now let’s create a .conf
file for the project. Go to the conf.d
directory:
Remove the default.conf
file, and create a new one for our project:
Inside of the urban-train.conf
file, insert the new server block:
Test the nginx.conf
:
Start the nginx
service and enable it so that it starts at boot:
Final Remarks
Everything should be working now. Do a final test, reboot the server and check if everything starts up normally:
Some things that may cause trouble:
- SELinux permission issues, read more here: SELinux Changes when Upgrading to RHEL 6.6 / CentOS 6.6
- The nginx user does not have permission to project folders
- PostgreSQL authentication method