sonic-meme

if your current deployment steps look like anything other than this:

git add .
git commit -m "update"
git push

Then you are in the right place to learn how to automate deploying your local git changes to your production domains.

This method will have your changes pushed to prod in seconds, not minutes, hours, and without any use of manual scp ,rsync, zipping files, etc.

prerequisites

  1. a Github account

First, make a new subdir in the root of your project, named .github

mkdir .github

in that dir, make a workflows dir

mkdir workflows

in that dir, make a new file, named deploy.yml

nano deploy.yml

This is the YAML file that will tell Github how to process your deployment

name: Deploy to EC2

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Install SSH key
      uses: shimataro/ssh-key-action@v2
      with:
        key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
        known_hosts: ${{ secrets.KNOWN_HOSTS }}

    - name: Deploy to EC2
      env:
        EC2_HOST: ${{ secrets.EC2_HOST }}
        EC2_USER: ${{ secrets.EC2_USER }}
        EC2_PORT: ${{ secrets.EC2_PORT }}
      run: |
        ssh -i $HOME/.ssh/id_rsa -o StrictHostKeyChecking=no -p $EC2_PORT $EC2_USER@$EC2_HOST '
          bash /home/youruser/myproject/deploy.sh
        '

Leave the youruser and myproject for now and update it later.

For github to process your request securely, you want to use strong encryption. We will select ed25519 as our encryption algorithm.

ssh-keygen -t ed25519

If you want to add a comment to your key, add -C "comment" to the command, this can help remind you what you made it for.


Ensure that you know where you are saving the new key to and give it a descriptive name:

~$ ssh-keygen -t ed25519 -C "demonstration"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/myusername/.ssh/id_ed25519): /home/myusername/.ssh/demonstration
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/myusername/.ssh/demonstration
Your public key has been saved in /home/myusername/.ssh/demonstration.pub
The key fingerprint is:
SHA256:FxztaBJmxzHT721RfPYIncRRdQET1ljDxJhdjS1OpDg demonstration
The key's randomart image is:
+--[ED25519 256]--+
|         .=+ X^%X|
|        +.o===O=X|
|       o oEo.= ++|
|        . oo. +..|
|        So.  . ..|
|         .    . o|
|               . |
|                 |
|                 |
+----[SHA256]-----+

notice I entered the path for the file when I made the key:

/home/myusername/.ssh/demonstration

so now the private keys name is 'demonstration' and its public key is 'demonstration.pub', and it is saved in my users .ssh folder

~$ ls -alph
...
drwx------  2 myusername   myusername   4.0K Oct  6 16:07 .ssh/
..
~$ cd .ssh
~/.ssh$ ls -alph
-rw-------  1 myusername myusername  399 Oct  6 16:07  demonstration
-rw-r--r--  1 myusername myusername   95 Oct  6 16:07  demonstration.pub

On github, add the new private key and create the repo secrets for your deployment

1. Add private key:

(Your Repo > Settings > Deploy keys)

Deploy-keys

  • When adding the private key, you may enable it as a 'read only' key if you do not want your remote domain to write changes to your repo. I always enable this as I will only push changes from local, not my domain.

2. Add secrets:

(Your Repo > Settings > Secrets and variables: Actions)

For this example I'm creating the following Actions secrets and variables:

  1. EC2_HOST: the domain (e.g. @[email protected])
  2. EC2_PORT: if you use a specific port for SSH enter it here
  3. EC2_PRIVATE_KEY: the plain text of the private key we just made
  4. EC2_USER: the username you use to perform daily tasks with on the domain.
  5. EC2_KNOWN_HOSTS: *known hosts is optional. you can scan your domains known hosts and provide github the known sha sums that you know your domain by, so that github will only continue if your domain provides one of those sha sums that your localhost recognizes.

automate-your-deployments-1.png

  • I have an extra secret "EC2_PRIVATE_KEY" that is not mentioned in the yaml script so just disregard that.

3. Add the public key to your domains users authorized_keys file:

# on local
cat demonstration.pub # copy the text of the public key

# on remote
nano ~/.ssh/authorized_keys
# make a newline and paste your public key
#CTRL + S to save changes, CTRL + X to close the file

So far we have created the deploy.yml, new ssh keys, and configured github actions. Now we must create the deploy.sh bash script.

In the root of your dir on localhost, create deploy.sh

cd myproject
nano deploy.sh

Here is an example deploy.sh:

#!/bin/bash
set -e

# Navigate to the project directory
cd /home/myusername/myproject

# Pull the latest changes
git pull origin main

# Function to stop the existing application
stop_app() {
    if pgrep -f goserver > /dev/null; then
        echo "Stopping existing application..."
        pkill -f goserver
        sleep 5
    fi
}

# Stop the existing application
stop_app

# Start the application in the background
nohup ./goserver > app.log 2>&1 &

# Wait for the application to start
sleep 5

# Check if the application is running
if pgrep -f goserver > /dev/null; then
    echo "Deployment completed successfully! goserver is running."
else
    echo "Deployment failed: goserver is not running"
    exit 1
fi

With this deploy.sh, we are essentially saying:

  1. Pull changes from your github repo to your remote domain
  2. Stop and restart the web service in the background
  3. Provide a status message
    Note: This script assumes that your web server is started/stopped by an executable script. In my case using a Golang backend webserver, I have a .exe that is named 'goserver', which performs tests and is compiled at runtime.
    If you are using a different backend web server just ensure that you are starting it similarly at this step.

After this is made, make it executable and push your changes to github:

chmod +x deploy.sh
git add . # Add all changes 
git commit -m "demonstration"
git push

Now we can go to the Actions tab under our repo:

actions

The actions are now being processed (small green dot):

actions-processing

Examine the actions status:

actions-steps

Verify completed actions deployment:

actions-completed

  • If you run into issues, ensure that the deploy.sh script is made executable on your remote host and that your account has the privileges to run the script.

That's it.

Your local changes are now pushed to prod.

I hope this helps your automate your deployments!