In this short tutorial, we will be learning how to automate deployment to a VPS via SSH using Github actions and a simple Python script.
LEVEL - 💻 💻 Intermediate - Advanced
To get started you will need the following.
Our goal is to automatically deploy the latest version of an application to a server each time we push to a certain branch. To do that we need to first prepare our server for our application. You should have your server set up and ready to go.
The workflow will run commands on a remote server via SSH. We need to create an SSH key and add it to the list of allowed keys on the server.
We prefer to generate fresh SSH keys for each of our servers. Generating the SSH key can be done on your local machine.
On your local machine, generate an SSH key
$ ssh-keygen -t ed25519 -C "[email protected]";
Copy the private key to your clipboard and add it as an environment variable in Github.
$ pbcopy < ~/.ssh/id_ed25519
1. Copy the public key to the server using ssh-copy-id
$ ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
2. Manually copy the public key to the server
>> copy keys to clipboard
$ pbcopy < ~/.ssh/id_ed25519.pub
or
$ pbcopy < ~/.ssh/id_rsa.pub
>> ssh into server and use text editor to paste contents in authorized_keys
$ nano ~/.ssh/authorized_keys
If you are not familiar with how to generate SSH keys we suggest you read this post from Github.
This section is out of the scope of this article but has been included for completeness.
Clone the repository to the server and set up the app is working as expected. For example, if we were cloning Advantch's sample fastapi project we would run the following.
$ mkdir demo
$ git clone [email protected]:advantch/fastapi-starter-template.git ./demo
$ cd fastapi-starter-template && docker-compose build
$ ufw allow 80
$ docker-compose up -d
mkdir core
- create a directory called demo to dump the contents of the repository into.git clone [email protected]:advantch/fastapi-starter-template.git ./demo
- clone the repo into the folder and build the stackufw allow 80
- expose port 80 to the outside worlddocker-compose up -d
- launch docker-compose in detached mode.In this first part, we will add a script to automate deployment tasks using Invoke. Invoke is a Python task execution tool & library. This is a personal preference. You could also use a bash script in place of this.
Create a file called tasks.py
in the root directory of your project.
from invoke import task
SERVER_APP_FOLDER = '/home/apps/demo'
@task
def deploy_app_to_server(c, docs=False, bytecode=False, extra=''):
"""
Pulls latest branch, rebuilds containers and runs migration command
"""
with c.cd(SERVER_APP_FOLDER):
c.run("echo 'Pulling latest commit and building containers'")
c.run("git pull")
c.run("docker-compose -f production.yml build")
c.run("echo 'Containers successfully build launching app'")
c.run("docker-compose -f production.yml run --rm django python manage.py migrate")
c.run("docker-compose -f production.yml up -d")
SERVER_APP_FOLDER = '/home/apps/demo'
- this is the name of the app folder for the application. Rename this appropriately.
@task
decorator marks the function as a task that can be run by Invoke. c.run("git pull")
- will pull the default branch from the server. This assumes you have already set up the server the first time as shown in step one.Add the following workflow to .github/workflows/deploy.yaml.
name: Deploy to demo app
on:
push:
branches:
- main_demo
jobs:
deploy-demo-app:
runs-on: ubuntu-latest
steps:
- name: Deploy to server
uses: fifsky/[email protected]
with:
host: 'demo.advantch.com'
user: 'apps'
key: ${{ secrets.PRIVATE_KEY }}
script: cd your-app-folder && python3 -m invoke deploy-demo-app-to-server
This workflow will run the job deploy-demo-app
on every push to the main_demo branch.
host: 'demo.advantch.com'
- replace this with your host (IP or domain).user: 'apps'
- set the SSH user name. e.g. 'apps'key
- defines the private key to use for loginscript
- defines the script which will run on the server.To get fast feedback, we can use the excellent act library to test workflows locally before deploying them to GitHub.
Head over to the GitHub page and follow the instructions on how to install act.
Once that is done, test the workflow to make sure everything is working.
Run act -l
to list available workflows.
$ act -l
>>
ID Stage Name
deploy-demo-app 0 deploy-demo-app
Test the workflow
$ export PRIVATE_KEY=$(cat ~/.ssh/id_ed25519)
$ act -j deploy-demo-app -s PRIVATE_KEY
>>
[Deploy to demo app/deploy-demo-app] 🚀 Start image=catthehacker/ubuntu:act-latest
[Deploy to demo app/deploy-demo-app] 🐳 docker run image=catthehacker/...
...
...
| To delete this message of the day: rm -rf /etc/update-motd.d/99-one-click
[Deploy to demo app/deploy-demo-app] ✅ Success - Deploy to server
export PRIVATE_KEY=$(cat ~/.ssh/id_ed25519)
- creates an environment variable named PRIVATE_KEY
and sets it to the private key generated earlier. act -j deploy-demo-app -s PRIVATE_KEY
- run the job deploy-demo-app passing in the PRIVATE_KEY
.
If everything went smoothly, you can commit and push to your remote repo on GitHub. The action will deploy the latest app to the server whenever you push to the main branch.
GitHub Actions in combination with automation scripts are powerful tools that you can use to automate all your software workflows and simplify your DevOps. We have included some additional reading materials below for areas we did not cover in detail.
Related Articles
All ArticlesSuccess
Error
Warning
Info