How to Set Up CI/CD for Your Django App Using GitHub Actions and Systemd
Sospeter Mong'are

Sospeter Mong'are @msnmongare

About: Software Engineer passionate about developing for the web

Location:
Kenya
Joined:
Nov 22, 2018

How to Set Up CI/CD for Your Django App Using GitHub Actions and Systemd

Publish Date: May 27
1 0

Setting up continuous deployment for your Django application can save you hours of manual server updates. In this guide, we’ll walk through how to automate deployment using GitHub Actions, SSH, and Systemd.

We’ll use a real-world example: a Django backend API hosted on a subdomain (api.example.com), deployed to a remote Ubuntu server.


Prerequisites

Before you begin, ensure you have:

  • A Django project hosted on GitHub.
  • A remote server (Ubuntu) with:

    • Python & pip
    • virtualenv
    • Gunicorn
    • Nginx configured for your app
  • SSH access to the server

  • Gunicorn configured as a systemd service

  • GitHub repository secrets setup


Step 1: Create a Gunicorn Systemd Service

On your server, create a systemd service for Gunicorn:

sudo nano /etc/systemd/system/django_app.service
Enter fullscreen mode Exit fullscreen mode

Paste this config:

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

[Service]
User=deployuser
Group=www-data
WorkingDirectory=/var/www/django_app
ExecStart=/var/www/django_app/venv/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/var/www/django_app/django_app.sock \
          project_folder.wsgi:application
Restart=always

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Reload and enable it:

sudo systemctl daemon-reload
sudo systemctl enable django_app
sudo systemctl start django_app
Enter fullscreen mode Exit fullscreen mode

Check status:

sudo systemctl status django_app
Enter fullscreen mode Exit fullscreen mode

Step 2: Add Sudo Access Without Password

Give the deployment user (deployuser) permission to restart Gunicorn without a password:

sudo visudo -f /etc/sudoers.d/deployuser
Enter fullscreen mode Exit fullscreen mode

Add this line:

deployuser ALL=(ALL) NOPASSWD: /bin/systemctl restart django_app
Enter fullscreen mode Exit fullscreen mode

Step 3: Add Secrets to GitHub Repository

Go to Settings > Secrets and variables > Actions > New repository secret and add:

Name Value
SSH_PRIVATE_KEY Your private key for SSH
SSH_USER The user (e.g., deployuser)
SSH_HOST Your server's IP or domain
PROJECT_PATH e.g., /var/www/django_app

🧪 Step 4: Add the GitHub Actions CI/CD Workflow

Create .github/workflows/deploy.yml in your repo:

name: Deploy Django backend api to Server

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout Code
      uses: actions/checkout@v3

    - name: Set up SSH
      uses: webfactory/ssh-agent@v0.7.0
      with:
        ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

    - name: Deploy to Server
      run: |
        ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'EOF'
          cd ${{ secrets.PROJECT_PATH }}
          git pull origin main
          source venv/bin/activate
          pip install -r requirements.txt
          python manage.py migrate --noinput
          python manage.py collectstatic --noinput
          sudo systemctl restart django_app
        EOF
Enter fullscreen mode Exit fullscreen mode

Step 5: Push Code and Watch the Magic

Now every time you push to the main branch, GitHub will:

  1. SSH into your server
  2. Pull the latest code
  3. Install dependencies
  4. Run database migrations
  5. Collect static files
  6. Restart Gunicorn

You can view workflow progress under Actions in your GitHub repo.


Bonus: Check Logs

To debug:

journalctl -u django_app
Enter fullscreen mode Exit fullscreen mode

🎉 Conclusion

With GitHub Actions + Gunicorn + systemd, you now have a robust deployment pipeline that:

  • Updates code automatically
  • Handles migrations and static files
  • Restarts the app with zero manual work

Let me know if you'd like a companion article on setting this up with Docker, GitLab CI, or for frontend apps too.

Comments 0 total

    Add comment