DEV Community

Victor Joseph
Victor Joseph

Posted on

How to deploy a Django app on an AWS EC2 instance

Today I'll be writing on how to deploy a Django app on an AWS EC2 instance. Ofcourse there are many ways to deploy a Django app to AWS so therefore we will be looking at one of the ways to do that.

The first thing you need to do is to log in to your AWS account and search for EC2. Click on it and it would take you to your EC2 dashboard.

Create security group

Next thing you need to do is to create a security group.
A security group is a virtual firewall that controls the inbound and outbound network traffic for one or more instances. It acts as a filter for the traffic that can reach the instances and specifies the types of traffic, such as HTTP, HTTPS, SSH, etc., that are allowed to access the instances.
To create a security group, on your EC2 dashboard under the resources section, click on security group

At the top right corner, click the "create security group" button and then give your security group a name and description. Scroll down and add your inbound rules as shown in the picture

image of security groups to add to EC2 instance
Once you've added that you can scroll down and create the security group. Do well to keep in mind the name of your just created security group we'll be needing it shortly

Create EC2 Instance

Now we have gotten that out of the way, it's now time to create our first EC2 instance. Head back to your EC2 dashboard and click on instances (running) and then click on launch instance at the top right corner. Give your instance a name and then select Ubuntu as your Application and OS Images (Amazon Machine Image). Make sure it's the free tier eligible one you selected. scroll down and double check that your instance type (either t2 or t3) is also a free tier eligible one. For the sake of simplicity of this tutorial, well leave out creating a key pair so just ignore that section and scroll down.
Now under Network settings, click on Select existing security group and then select the security group you created earlier from the first section of this post (hope you still remember the name?) from the drop down. Leave every other setting in default and click on launch instance at the bottom right. If you did every thing right, your instance should be up and running in a few seconds.

Connect to your instance

Back on your EC2 dashboard, click on instances and you should see your just created instance, ensure that the status of your instance is running before you proceed to the next steps. Now to connect to your instance, select the instance you want to connect to and the click on connect. Click on the connect button again and you should be redirected to a new tab that has connected to your instance.

Now the main work 😅

Now that we have connected to our EC2 instance, we can now start the dirty work. First we have to install some packages

sudo apt update
sudo apt install python3-venv python3-dev libpq-dev postgresql postgresql-contrib nginx curl
Enter fullscreen mode Exit fullscreen mode

This command will install a necessary packages you need to create virtual environments for your Python projects, build Gunicorn, create a Postgres database system and the libraries needed to interact with it, and the Nginx web server.

Create the PostgreSQL Database and User

Next we have to create a PostgreSQL database for our django application. If you are fine using the default sqlite database, feel free to skip this section

Log into an interactive Postgres session by typing:

sudo -u postgres psql
Enter fullscreen mode Exit fullscreen mode

Next, create a database for your project:

CREATE DATABASE djangodb;
Enter fullscreen mode Exit fullscreen mode

Next, you have to create a database user for your project.

CREATE USER djangouser WITH PASSWORD 'put_a_secure_password';
Enter fullscreen mode Exit fullscreen mode

Django needs the following parameters for its database connections so let's add them

ALTER ROLE djangouser SET client_encoding TO 'utf8';
ALTER ROLE djangouser SET default_transaction_isolation TO 'read committed';
ALTER ROLE djangouser SET timezone TO 'UTC';
Enter fullscreen mode Exit fullscreen mode

Next, give the new user access to control the new database.

GRANT ALL PRIVILEGES ON DATABASE djangodb TO djangouser;
Enter fullscreen mode Exit fullscreen mode

Create a Python Virtual Environment for your Project

Up next to create a virtual environment and install the Python requirements within the virtual environment for easier management.

python3 -m venv venv
Enter fullscreen mode Exit fullscreen mode

Next you activate the virtual environment

source venv/bin/activate
Enter fullscreen mode Exit fullscreen mode

Setting up Your django project.

After that the virtual environment has been activated, the next thing is to clone the github repository you want to deploy. You can do that using the following commands below

git clone https://github.com/sampleusername/myproj.git
Enter fullscreen mode Exit fullscreen mode

Next is to install some necessary packages in other to run a basic django app.

pip install django gunicorn psycopg2-binary
Enter fullscreen mode Exit fullscreen mode

You can also install other libraries and packages in your requirements.txt file

cd myproj/
pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Configure the Project Settings

You should make sure that you have setup your database variables in your settings.py for the database connection to the postgres database you created earlier. And example configuration is shown below. Open the settings file in a text editor. You can do that using nano

nano myproj/myproj/settings.py
Enter fullscreen mode Exit fullscreen mode

Then you look for the database connection and make the necessary changes using your own details

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'djangodb',
        'USER': 'djangouser',
        'PASSWORD': 'put_a_secure_password',
        'HOST': 'localhost',
        'PORT': '',
    }
}

Enter fullscreen mode Exit fullscreen mode

You should also set your allowed hosts

ALLOWED_HOSTS = ['Your_Public_IPv4 address', 'domain_name', . . ., 'localhost']
Enter fullscreen mode Exit fullscreen mode

If you are using a custom domain name, after you have added the domain name to your allowed host, you would also need to add a host record. You can use the sample picture below to guide you on how to set it up.

picture of adding your host records to namecheap

You can also use also decide to use Route 53 and set up an elastic IP address if you wish. It is actually the recommended way to setup your custom domain name. you can check out this tutorial on how to do that.

Migrate your django migrations

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

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

Set up Supervisor

The next thing we would want to do is to install supervisor. Now supervisor is there to ensure that our application keeps on running smoothly in the background.
First let's install it

sudo apt-get install supervisor
Enter fullscreen mode Exit fullscreen mode

Then we need to configure a Gunicorn process to ensure that our server (Gunicorn) starts automatically with the system and that it can automatically restart if for some reason it exits unexpectedly. To do that, we need to change directory to where the configuration files should be placed. You can do that by

cd /etc/supervisor/conf.d 
Enter fullscreen mode Exit fullscreen mode

Then create a guincorn.conf file

sudo nano gunicorn.conf
Enter fullscreen mode Exit fullscreen mode

paste the following code

[program:gunicorn]
directory=/home/ubuntu/myproj
command=/home/ubuntu/venv/bin/gunicorn --workers 3 --bind unix:/home/ubuntu/myproj/app.sock myproj.wsgi:application 
autostart=true
autorestart=true
stderr_logfile=/var/log/gunicorn/gunicorn.err.log
stdout_logfile=/var/log/gunicorn/gunicorn.out.log
Enter fullscreen mode Exit fullscreen mode

Make sure to change all instances of myproj to your actuall project name

save and close the file once you're done. You can do so by pressing ctrl o then press enter. To close the file press ctrl x

Once we have done that, we'll need to create the log file directory.

sudo mkdir /var/log/gunicorn
Enter fullscreen mode Exit fullscreen mode

Finally we then need to notify the supervisor of the changes we just made using supervisorctl

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start all
sudo supervisorctl status all
Enter fullscreen mode Exit fullscreen mode

Make sure that when you check for your status it shows running. It it's not, you'll need to debug your code for errors. You can check for errors in your log file in /var/log/gunicorn

Below are some useful commands you can use to debug your code

# to check the status of our processes
sudo supervisorctl status <program_name>

# example
sudo supervisorctl status gunicorn
my_proj                          RUNNING   pid 1412, uptime 7:59:29

# to check status of all running process 
sudo supervisorctl status all


# to start, stop, restart all or some of the processes
sudo supervisorctl start <program_name|all>
sudo supervisorctl restart <program_name|all>
sudo supervisorctl stop <program_name|all>
Enter fullscreen mode Exit fullscreen mode

Setup Nginx

First of we need to make some changes to the nginx conf file in other to avoid permission denied errors. To that change directory to where the file is stored

cd /etc/nginx

#then open the conf file
sudo nano nginx.conf
Enter fullscreen mode Exit fullscreen mode

Once the file is opened, change the www-data in the first line of the file to root. Close and save.

With that out of the way we can now go ahead to create a configuration file for our django application in the sites-available directory

sudo nano /etc/nginx/sites-available/django.conf
Enter fullscreen mode Exit fullscreen mode

then paste the settings below

replace appropriately with your aws public ip address and custom domain name if you have and change all instances of my proj to your actual project name

server{
    listen 80;
    server_name your_public_ip your_custom_domain;
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/ubuntu/myproj;
    }
    location / {
        include proxy_params;
        proxy_pass http://unix:/home/ubuntu/myproj/app.sock;

    }
}
Enter fullscreen mode Exit fullscreen mode

Let's do some explanations

  1. The first location tells Nginx to ignore any problems with finding a favicon.

  2. The second location tells where to find the static assets that you collected in your /myproj/static directory. All of these files have a standard URI prefix of /static, so you can create a location block to match those requests

  3. The third finally creates a location / {} block to match all other requests. Inside of this location, includes the standard proxy_params file included with the Nginx installation which then passes the traffic directly to the Gunicorn socket

You can close the file and save it.
Next you need to test our Nginx configuration for syntax errors

sudo nginx -t
Enter fullscreen mode Exit fullscreen mode

Lastly, you need to enable the file by linking it to the sites-enabled directory. To do that,

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
Enter fullscreen mode Exit fullscreen mode

And last but not the least you can go ahead to restart your nginx server

sudo service nginx restart
Enter fullscreen mode Exit fullscreen mode

You can now open your website by visiting your public ip address or using your custom domain link and your site should be live

Securing connections with HTTPS

start by installing certbot

sudo apt install python-certbot-nginx
Enter fullscreen mode Exit fullscreen mode

next you need to obtain an SSL Certificate

sudo certbot --nginx -d myawesomedomain.com
Enter fullscreen mode Exit fullscreen mode

You will then be prompted to provide an email, then press [ENTER]
Next you will need to accept the terms of service.
Next you will need to decide if you want to opt into some digital marketing.

Let’s Encrypt’s certificates are only valid for ninety days, this is meant to force users to automate renewal of the certificates. Luckily certbot takes care of this for us. However we still need to verify this.

sudo certbot renew --dry-run
Enter fullscreen mode Exit fullscreen mode

Thank you for reading.

Top comments (0)