CI/CD Django Deployment with GitHub Actions
Automating your Django deployment with CI/CD eliminates manual errors and speeds up your release process. In this guide, I'll show you how to set up a complete GitHub Actions pipeline that tests, builds, and deploys your Django application automatically.
Why CI/CD for Django?
Continuous Integration and Deployment provides:
- Automated testing - Catch bugs before they reach production
- Consistent deployments - Same process every time
- Faster releases - Deploy with a single git push
- Quality assurance - Automated code checks and formatting
Architecture Overview
Our pipeline follows a three-stage workflow:
Job 1: Test & Quality Checks
├── Run Django tests
├── Check code with Ruff
└── Verify dependencies
↓
Job 2: Deploy to Remote Server
├── SSH into server
├── Pull latest code
├── Build containers
└── Restart services
↓
Job 3: Deployment Notification
└── Confirm successful deployment
Django Project Structure
A typical Django project using pyproject.toml looks like this:
[project]
name = "myproject"
version = "1.0.0"
description = "Django application with Docker deployment"
requires-python = ">=3.11"
dependencies = [
"django>=5.0",
"gunicorn>=21.2.0",
"psycopg2-binary>=2.9.9",
"python-dotenv>=1.0.0",
]
[project.optional-dependencies]
dev = [
"ruff>=0.1.0",
"pytest>=7.4.0",
"pytest-django>=4.7.0",
]
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W"]
ignore = ["E501"]
GitHub Actions Workflow
Create .github/workflows/deploy.yml in your repository:
name: Django CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
name: Test & Quality Checks
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .[dev]
- name: Run Ruff linter
run: |
ruff check .
- name: Run Ruff formatter
run: |
ruff format --check .
- name: Run Django tests
run: |
python manage.py test
env:
DJANGO_SETTINGS_MODULE: myproject.settings
SECRET_KEY: test-secret-key-for-ci
DATABASE_URL: sqlite:///db.sqlite3
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Deploy to server
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /home/${{ secrets.SERVER_USER }}/myproject
git pull origin main
docker compose down
docker compose up --build -d
docker compose exec -T web python manage.py migrate
docker compose exec -T web python manage.py collectstatic --noinput
notify:
name: Deployment Notification
runs-on: ubuntu-latest
needs: deploy
if: always()
steps:
- name: Notify deployment status
run: |
if [ "${{ needs.deploy.result }}" == "success" ]; then
echo "✅ Deployment to ${{ secrets.DOMAIN }} successful!"
else
echo "❌ Deployment failed!"
exit 1
fi
Configure GitHub Secrets
GitHub Secrets store sensitive information securely for your workflows.
Generate SSH Key Pair
Create a dedicated SSH key for GitHub Actions:
# On your local machine
ssh-keygen -t ed25519 -C "github-actions" -f ~/.ssh/github_actions
Add Public Key to Remote Server
Copy the public key to your server:
# On Linux - Display public key
cat ~/.ssh/github_actions.pub
# On Windows - Display public key
notepad ~/.ssh/github_actions.pub
# Copy the entire output (starts with "ssh-ed25519")
Add it to your remote server:
# On the REMOTE server
echo "PASTE_PUBLIC_KEY_HERE" >> ~/.ssh/authorized_keys
# Verify permissions
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh
Add Secrets to GitHub
Navigate to: GitHub → Repository → Settings → Secrets and variables → Actions → New repository secret
Add these secrets:
| Secret Name | Value | Description |
|---|---|---|
SERVER_IP |
203.0.113.42 |
Your remote server IP address |
SERVER_USER |
deploy |
SSH username on server |
SSH_PRIVATE_KEY |
-----BEGIN OPENSSH... |
Full private key content |
DOMAIN |
example.com |
Your production domain |
Getting the private key:
# On Linux
cat ~/.ssh/github_actions
# On Windows
notepad ~/.ssh/github_actions
Copy the entire content including the -----BEGIN and -----END lines.
Pre-Deployment Checklist
Before pushing to production, run these checks in your development environment.
Run Tests Locally
Ensure all tests pass:
python manage.py test
Check Code Quality
Lint and format your code:
# Lint and auto-fix issues
ruff check --fix .
# Format code
ruff format .
Verify Django Configuration
Run Django's deployment checks:
# Apply migrations
python manage.py migrate
# Check for deployment issues
python manage.py check --deploy
Triggering Deployments
Once configured, deployments are automatic:
# Make your changes
git add .
git commit -m "feat: add new feature"
# Push to main branch (triggers CI/CD)
git push origin main
The pipeline will:
1. Run tests and quality checks
2. Deploy to your server if tests pass
3. Notify you of the deployment status
Monitoring Deployments
View your workflow runs:
- Go to your GitHub repository
- Click the Actions tab
- Select your workflow run
- View logs for each job
Check deployment on your server:
# View running containers
docker compose ps
# Check application logs
docker compose logs -f web
# Verify deployment
curl https://your-domain.com
Key Takeaways
GitHub Actions automates your entire deployment pipeline, from testing to production, with every git push to the main branch.
CI/CD best practices:
- ✓ Always run tests before deployment
- ✓ Use dedicated SSH keys for automation
- ✓ Store secrets securely in GitHub
- ✓ Test locally before pushing
- ✓ Monitor deployment logs
- ✓ Keep your workflow file versioned
Your Django application now deploys automatically with confidence! 🚀