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!

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
- Go to GitHub → Repository → Settings → Webhooks.
- Click "Add Webhook".
- Payload URL:
http://your-ec2-public-ip:5000/webhook
- Content type:
application/json
- Trigger events: Select "Just the push event".
- 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! 🚀