Deploy a Django application through Github Actions

Hi everyone,

Here is a small article on how I successfully deployed my Django application through Github actions. Basically, what I needed was pretty simple, as soon as I push a new commit (on master), I want to:

  • connect through SSH on my remote server
  • restart my cfptime service (which will do all the magic)

My cfptime.org project is something like ~3 years old and at the beginning, I was deploying by hand and I created a bash script in order to ease this part and this is what it looked like:

#!/bin/bash
cd /path/to/cfptime
git pull
source env/bin/activate
python manage.py makemigrations;
python manage.py migrate;
python manage.py collectstatic --noinput;
gunicorn --access-logfile - --workers 1 --bind unix:/path/to/cfptime/cfptime.sock cfptime.wsgi:application

By using a socket file (cfptime.sock), I can access it locally without having to open a port (even on the localhost). A bit off-topic but my nginx configuration file looks like this:

server {
    listen 443;
    server_name api.cfptime.org;

    location /static/  {
        alias /path/to/cfptime/cfptime/static/;
    }

    location / {
        proxy_pass         http://unix:/path/to/cfptime/cfptime.sock:/;
        proxy_redirect     off;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }

    location = / {
        return 301 https://api.cfptime.org/api/docs;
    }
}

Later on, I created a systemd service allowing me to restart the service even more easily:

[Unit]
Description=CFP Time daemon
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/cfptime
ExecStart=/path/to/cfptime/launch.sh

[Install]
WantedBy=multi-user.target

I was then able to restart automatically cfptime with a simple: service cfptime restart !

Finally, I used Github actions in order to restart my service automatically, which will:

  • Pulls the code from Github
  • Performs all Django migrations (if applicable)
  • Collect static files (if applicable)
  • And finally, restart the app :)

My Github action looks like this:

name: remote ssh command
on: [push]
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
    - name: executing remote ssh commands using password
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USER }}
        key: ${{ secrets.PRIVATE_KEY }}
        port: ${{ secrets.PORT }}
        script: |
          sudo service cfptime restart

In order to make this work, you just need to specify the HOST, USER, PRIVATE_KEY and PORT variables in your repository's secrets and… you should be good to go!

Happy deployment :)