Site icon Shuru

Deploy Django on AWS EC2 – A Complete Guide

django

Introduction

Deploying a Django application to production can seem daunting, especially with cloud infrastructure. AWS EC2 offers a powerful and flexible environment for hosting Django apps, providing complete control over the deployment process. This guide outlines the steps to set up and deploy a Django project on an EC2 instance from scratch.

The guide covers foundational steps such as:

Let’s dive in and get your Django project live on AWS!

Requirement and specification

Infrastructure Requirements
CI/CD Pipeline

Django basic setup

In this section, we will walk through the essential steps to get a Django project up and running, along with a simple health check API at /ping. This route will respond with a status message to verify that the application is working correctly.

Prerequisites

  1. Check if Python is Installed

Run python –version or python3 –version in the terminal. If no version appears, install Python as follows:

brew install python@3.#Replace X with the versionCode language: PHP (php)
  1. Install pip (if missing)

Use Python’s ensurepip module to install pip:

python -m ensurepip --upgrade

Step 1: Install Django and Create a Project

The following steps outline how to set up a virtual environment and install Django:

  1. Install virtualenv (if it’s not already installed):
pip install virtualenv
  1. Create and activate a virtual environment:
python -m venv venvsource venv/bin/activate # For Linux/macOS
venv\Scripts\activate #For WindowsCode language: PHP (php)
  1. Install Django:
pip install django
  1. Create a New Django Project

Next, set up a new Django project and navigate into its directory by running the following commands:

# Create a new Django project django-admin startproject myproject
# Run initial migrations to set up the database python manage.py migrate
# (Optional) Create a new app for the project python manage.py startapp healthcheckCode language: PHP (php)

Step 2: Add ping Route

  1. To set up a simple health check route, open the urls.py file in your project directory (myproject/urls.py) and update it with the following code:
from django.urls import path from django.http import JsonResponse 
# Simple health check function def ping(request):   
return JsonResponse({"status": "ok", "message": "Service is running"}) urlpatterns = [ path('ping', ping), 
# Health check route ]Code language: PHP (php)
  1. Ensure the settings are ready for local testing. Open myproject/settings.py and add the following configuration if it’s not already present. Now we’ll set it to * which means allow requests from everywhere, localhost in our case.
ALLOWED_HOSTS = ['*']Code language: JavaScript (javascript)

Step 3: Run the Django Server

Now, let’s test the application locally:

python manage.py runserver 0.0.0.0:8000Code language: CSS (css)

To verify that the endpoint is working, visit http://localhost:8000/ping in a web browser or use curl:

curl http://localhost:8000/pingCode language: JavaScript (javascript)

If everything is set up correctly, the expected response will be:

{
  "status": "ok",    "message": "Service is running"
}Code language: JSON / JSON with Comments (json)

With the basic Django setup ready, you have a foundation for your application. Next, we’ll set up the VPC and EC2 instance to deploy it on AWS.

Cloud setup

This section covers the necessary steps to set up an EC2 instance within a private subnet inside a VPC (Virtual Private Cloud), along with an Internet-facing Application Load Balancer (ALB) to route external traffic. The ALB will act as a gateway between the public internet and your private EC2 instance, ensuring that the EC2 instance stays protected and only accessible via the ALB.

  1. Setting up VPC
    1. Navigate to the AWS console, search VPC and select create VPC.
    2. From the page, select VPC and more. This will create all the required subnets (both private and public), set AZs, route tables and Internet Gateway all at once.
    3. Enter the name and change the CIDR block if needed.
    4. Change any value if needed such as number of NAT gateway, number of subnet or AZs and click Create VPC, it should be created within a few minutes.
  2. EC2 setup
    1. Navigate to the AWS console, search for EC2, and click Launch Instance.
    2. Enter the instance name, select Ubuntu 22.04 as the OS image, and set storage to a minimum of 30 GB.
    3. Choose the created VPC and a private subnet, disable auto-assign public IP.
    4. Create a new security group to allow access only from the VPC CIDR block.
    5. Under Advanced settings, attach a role for SSM connection. Create a role with the AmazonSSMManagedInstanceCore policy if needed.
    6. Click Launch, the instance will be operational in a few minutes.
  3. AWS Application Load balancer setup
    1. Navigate to the AWS console, search Load Balancer and click on create load balancer, select Application load balancer.
    2. Give it a name, select scheme as internet facing, choose the IP type as per the VPC, change the VPC to the one we created, select AZs and create security group to allow traffic from all IPs to hit the load balancer.
    3. In the listener and routing section, create a target group using the EC2 instance we just created, set the port where the server on EC2 is running. 
    4. Set protocol to http on port 80, default action as forward to the target group just created and click on Create load balancer, it should be up and running in a few minutes.

With the cloud environment configured, the next step is to set up Gunicorn to serve the django application. 

Gunicorn

Gunicorn (Green Unicorn) is a Python WSGI HTTP server that allows your Django application to handle multiple concurrent requests efficiently. While Django’s built-in development server is useful for local testing, it’s not suitable for production. Gunicorn ensures that your app performs well under load by running multiple worker processes.

Gunicorn setup

  1. Install Gunicorn within your virtual environment:
pip install gunicorn
  1. Now, navigate to your Django project folder and run Gunicorn with:
gunicorn --bind 0.0.0.0:8000 myproject.wsgi:applicationCode language: CSS (css)

Here:

You can now test your app by visiting http://<your-server-ip>:8000

  1. Creating a Systemd Service File

To keep Gunicorn running in the background and start it automatically on system boot, we’ll create a systemd service.

  1. Create a new service file at /etc/systemd/system/myproject.service
  2. Add the following content to the file:
[Unit]
Description=Gunicorn instance to serve Django project
After=network.target

[Service]
User=user-name
Group=group-name
WorkingDirectory=/path/to/your/project
ExecStart=/path/to/your/venv/bin/gunicorn --workers 3 --bind 0.0.0.0:8000 myproject.wsgi:application
Restart=always
[Install]
WantedBy=multi-user.targetCode language: JavaScript (javascript)

Explanation:

Running Gunicorn in the Background

Now that we have the service file, follow these steps to start and enable Gunicorn:

  1. Reload systemd to apply the new service file:
sudo systemctl daemon-reload
  1. Start the Gunicorn service:
sudo systemctl start myproject
  1. Enable the service to start on boot:
sudo systemctl enable myproject
  1. Check the status of the service
sudo systemctl status myproject

If everything is configured correctly, you should see Gunicorn running. Now, even if the server restarts, Gunicorn will launch automatically to serve your Django app.

With Gunicorn configured, your Django application is now ready to handle multiple requests efficiently in a production environment. 

With Gunicorn configured, the last and final step is setting up CI/CD for seamless deployment.

CICD

In this section, we’ll implement a CI/CD (Continuous Integration and Deployment) pipeline using GitHub Actions and AWS CodeDeploy. We’ll also store sensitive environment variables securely using AWS Parameter Store and inject them into the .env file on the EC2 instance during deployment.

This setup ensures that every time you push new code to the main branch, the latest version is automatically deployed to your EC2 instance.

1. Setting up AWS CodeDeploy

  1. Navigate to the AWS console and search for CodeDeploy. Click Create Application.
  2. Enter the application name and select EC2/On-Premises as the compute platform, then click Create.
  3. Open the application just created and create a deployment group. Enter the basic details for the group, deployment type as in place, attach a role with AWSCodeDeployFullAccess policy.

2. Install the CodeDeploy agent:

The CodeDeploy agent needs to be installed on the Ubuntu EC2 instance. This agent is a software package that runs on the instance and interacts with CodeDeploy to deploy the application. The CodeDeploy agent can be installed by running the following script on the EC2 instance:

#!/bin/bash#install.sh
# This installs the CodeDeploy agent and its prerequisites on Ubuntu 22.04.
sudo apt-get update
sudo apt-get install ruby-full ruby-webrick wget -y
cd /tmp
wget <a href="https://aws-codedeploy-ap-southeast-1.s3.ap-southeast-1.amazonaws.com/releases/codedeploy-agent_1.3.2-1902_all.deb">https://aws-codedeploy-ap-southeast-1.s3.ap-southeast-1.amazonaws.com/releases/codedeploy-agent_1.3.2-1902_all.deb</a>
mkdir codedeploy-agent_1.3.2-1902_ubuntu22
dpkg-deb -R codedeploy-agent_1.3.2-1902_all.deb codedeploy-agent_1.3.2-1902_ubuntu22
sed 's/Depends:.*/Depends:ruby3.0/' -i ./codedeploy-agent_1.3.2-1902_ubuntu22/DEBIAN/control
dpkg-deb -b codedeploy-agent_1.3.2-1902_ubuntu22/
sudo dpkg -i codedeploy-agent_1.3.2-1902_ubuntu22.deb
systemctl list-units --type=service | grep codedeploy
sudo service codedeploy-agent statusCode language: PHP (php)

Run the script using command bash install.sh

3. Add a new parameter:

  1. Go to the AWS Systems ManagerParameter StoreCreate Parameter.
  2. Choose Standard Parameter.
  3. Enter a name (e.g., /myproject/DEBUG) and a value (True or other values like database credentials).
  4. Set the type to String or SecureString for sensitive data.
  5. Add other environment variables similarly (e.g., /myproject/DB_HOST, /myproject/DB_NAME).

4. Creating a GitHub Actions Workflow: 

We will create a GitHub Actions workflow to automate deployment. In your project, create the following file:

/.github/workflows/main.yml

name: Deployment name

on:
  workflow_dispatch:
    inputs:
      tags:
        description: 'Deployment name'
        required: <strong>true</strong>
        type: string
  run-name: ${{ inputs.tags }}
  jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }}
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          ref: ${{ github.ref }}

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4.0.2
        with:
          aws-region: ${{ env.AWS_REGION }}
          aws-access-key-id: ${{ env.AWS_ACCESS_KEY }}
          aws-secret-access-key: ${{ env.AWS_SECRET_KEY }}

      - name: Store env variables in AWS Systems Manager Parameter Store
        run: aws ssm put-parameter --name "key_name" --value "${{ secrets.KEY_VALUE }}" --type "String" --overwrite

      - name: Create CodeDeploy Deployment
        run: |
          aws deploy create-deployment \
            --application-name 'application_name' \
            --deployment-group-name 'deployment_group_name' \
            --revision '{"revisionType":"GitHub","gitHubLocation":{"repository":"${{ github.repository }}","commitId":"${{ github.sha }}"}}' \
            --output json > deployment.json
            echo deployment.json

      - name: Extract deployment ID
        id: deployment
        run: |
          DEPLOYMENT_ID=$(jq -r .deploymentId deployment.json)
          echo "DEPLOYMENT_ID=$DEPLOYMENT_ID" >> $GITHUB_ENV

      - name: Wait for deployment to complete
        id: wait_for_deployment
        run: |
          DEPLOYMENT_STATUS=$(aws deploy get-deployment --deployment-id ${{ env.DEPLOYMENT_ID }} --query "deploymentInfo.status" --output text)
          echo "Deployment status: $DEPLOYMENT_STATUS"
          while [[ "$DEPLOYMENT_STATUS" != "Succeeded" && "$DEPLOYMENT_STATUS" != "Failed" ]]; do
            echo "Waiting for deployment to complete..."
            sleep 30
            DEPLOYMENT_STATUS=$(aws deploy get-deployment --deployment-id ${{ env.DEPLOYMENT_ID }} --query "deploymentInfo.status" --output text)
            echo "Deployment status: $DEPLOYMENT_STATUS"
          done
          if [[ "$DEPLOYMENT_STATUS" == "Succeeded" ]]; then
            echo "Deployment succeeded."
          elif [[ "$DEPLOYMENT_STATUS" == "Failed" ]]; then
            echo "Deployment failed."
            exit 1
          fiCode language: PHP (php)

5. Creating appspec.yml for AWS Codedeploy

CodeDeploy uses a YAML file which by default is named appspec.yml and found on source code root.

Create this file with the following content.

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ubuntu/your_project

hooks:
  AfterInstall:
    - location: scripts/deploy.sh
      timeout: 300
      runas: ubuntu

6. Deploying the new changes

The AfterInstall hook is utilized to execute a script following a successful AWS CodeDeploy deployment. We will leverage this hook to retrieve the environment variables saved during deployment and subsequently restart the server using a deploy.sh script.

#!/bin/bash# deploy.sh
KEY_VALUE=$(aws ssm get-parameter --name "key_name" --query "Parameter.Value" --output text --region "your_aws_region")
echo "" > /home/ubuntu/your_project/.envecho "KEY_NAME= $KEY_VALUE" >> /home/ubuntu/your_project/.env
sudo systemctl restart your_project.serviceCode language: PHP (php)

Conclusion

Deploying a Django application on AWS with EC2, CodeDeploy, and GitHub Actions can be simplified with a clear approach. This guide covered setting up the core infrastructure: configuring a secure VPC, creating subnets, and launching an EC2 instance in a private subnet. We integrated an Application Load Balancer (ALB) for public traffic routing and used Gunicorn as the app server, automating deployments with GitHub Actions and CodeDeploy. Sensitive data is managed securely with AWS Parameter Store, ensuring a flexible, scalable, and production-ready setup.With these steps, you’re ready to confidently build, deploy, and manage your Django app on AWS. Happy deploying! 🚀

Read more shuru tech blogs here

Authors

Exit mobile version