April 27, 2025career

Automating Django Deployment on AWS EC2 with GitHub Webhooks

In this guide, we’ll walk you through how to automatically deploy a Django application running on an AWS EC2 instance whenever you push changes to a GitHub repository. We’ll use GitHub Webhooks, a Flask webhook listener, a Bash deployment script, and systemd services to make it happen. By the end, your Django app will update itself with every new commit!

Featured image for Automating Django Deployment on AWS EC2 with GitHub Webhooks

Step 1: Setting Up Your Django Application on EC2

Before automating deployments, we need to have Django running on AWS EC2. Ensure you have:

  • A Django project hosted in a GitHub repository.
  • An EC2 instance with SSH access.
  • Gunicorn as the WSGI server.
  • Nginx as the reverse proxy.
  • A virtual environment for Python dependencies.

1.1 Connect to Your EC2 Instance

ssh -i your-ec2-key.pem ubuntu@your-ec2-public-ip

1.2 Install Required Packages

sudo apt update && sudo apt upgrade -y
sudo apt install python3-pip python3-venv nginx git -y

1.3 Clone Your Django Project

Navigate to your deployment directory and clone your repository:

cd /home/ubuntu
git clone git@github.com:your-username/your-django-repo.git blog-backend
cd blog-backend

1.4 Create and Activate a Virtual Environment

python3 -m venv env
source env/bin/activate
pip install -r requirements.txt

1.5 Apply Migrations and Collect Static Files

python manage.py migrate
python manage.py collectstatic --noinput

Step 2: Setting Up Gunicorn and Nginx

2.1 Create Gunicorn Systemd Service

sudo nano /etc/systemd/system/gunicorn.service

Paste the following:

[Unit]
Description=Gunicorn daemon for Django Project
After=network.target

[Service]
User=ubuntu
Group=ubuntu
WorkingDirectory=/home/ubuntu/blog-backend
ExecStart=/home/ubuntu/blog-backend/env/bin/python3 -m gunicorn --workers 3 --bind unix:/home/ubuntu/blog-backend/gunicorn.sock blog.wsgi:application
Restart=always
Environment="PATH=/home/ubuntu/blog-backend/env/bin"

[Install]
WantedBy=multi-user.target

Enable and start Gunicorn:

sudo systemctl daemon-reload
sudo systemctl start gunicorn
sudo systemctl enable gunicorn

2.2 Configure Nginx

sudo nano /etc/nginx/sites-available/blog-backend

Paste the following:

server {
listen 80;
server_name your_domain_or_public_ip;

location / {
proxy_pass http://unix:/home/ubuntu/blog-backend/gunicorn.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location /static/ {
alias /home/ubuntu/blog-backend/static/;
}

location /media/ {
alias /home/ubuntu/blog-backend/media/;
}
}

Enable and restart Nginx:

sudo ln -s /etc/nginx/sites-available/blog-backend /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx

Step 3: Automating Deployment with GitHub Webhooks

3.1 Create a Deployment Script

Create a Bash script to pull new changes and restart services:

sudo nano /home/ubuntu/deploy.sh
#!/bin/bash

PROJECT_DIR="/home/ubuntu/blog-backend"
GIT_BRANCH="main"

cd $PROJECT_DIR || exit
git reset --hard
git pull origin $GIT_BRANCH
source env/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py collectstatic --noinput
sudo systemctl restart gunicorn
sudo systemctl restart nginx

Make it executable:

sudo chmod +x /home/ubuntu/deploy.sh
sudo chown ubuntu:ubuntu /home/ubuntu/deploy.sh

3.2 Set Up a Flask Webhook Listener

Install Flask:

pip install flask

Create a webhook script:

sudo nano /home/ubuntu/webhook.py
from flask import Flask, request
import subprocess
import logging

app = Flask(__name__)
logging.basicConfig(filename='/home/ubuntu/webhook.log', level=logging.DEBUG)

@app.route("/webhook", methods=["POST"])
def webhook():
try:
app.logger.info("Webhook received: %s", request.json)
subprocess.Popen(["/bin/bash", "/home/ubuntu/deploy.sh"])
return "Deployment triggered!", 200
except Exception as e:
app.logger.error("Error in webhook: %s", str(e))
return "Internal Server Error", 500

if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)

3.3 Set Up Webhook as a Service

sudo nano /etc/systemd/system/webhook.service
[Unit]
Description=GitHub Webhook Listener
After=network.target

[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu
ExecStart=/home/ubuntu/env/bin/python3 /home/ubuntu/webhook.py
Restart=always
Environment="PATH=/home/ubuntu/env/bin"

[Install]
WantedBy=multi-user.target

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl start webhook
sudo systemctl enable webhook

3.4 Add Webhook in GitHub

  1. Go to GitHub → Repository → Settings → Webhooks.
  2. Click "Add Webhook".
  3. Payload URL: http://your-ec2-public-ip:5000/webhook
  4. Content type: application/json
  5. Trigger events: Select "Just the push event".
  6. Click "Add Webhook".

Conclusion

Now, every time you push changes to GitHub, the webhook will trigger the deployment script, which pulls the latest changes, installs dependencies, runs migrations, collects static files, and restarts services. Your Django app is now fully automated! 🚀

Share:
Reading time:3 min read