Deployment with GitHub Actions
January 21, 2025
So to make my life easier and automate the process of updating this very website you are currently on, I have decided to look into GitHub Actions. The base idea behind the process was to have an automated build job, that runs the Jekyll build script (see Jekyll article for more information). The automatic build job was to be followed by a manual deploy job, which send the built files to my hosting provider via SFTP.
First I had to learn a bit about GitHub actions. As it turns out, the general approach is pretty simple. All you need is a .github/workflows directory at the root of your project. In this directory, you can create YAML files that describe the various actions to be executed in your repository.
In my case, I wanted a build job that takes the current state of the main branch and builds the _site directory from it. Initially I was thinking about having the job push the built file into a separate branch. After tinkering around with the idea for a while, struggling to get the script going, then realizing I had added the _site directory to my .gitignore file, so the script couldn’t detect any changes to push. When I finally ended up facing a permission denied error, I’ve decided to divert from this idea. The script was now to generate an artifact, which I could manually download and upload into the file server of the hosting provider for this website.
The final script for this job looked like this:
However… Since you’ve read the title of this article, you know I couldn’t stop there. Once I had the artifact in my hands, and had to manually upload and extract it onto the file server… I realized I’d be too lazy to do that. So the natural next step was to have another GitHub Action, which essentially somehow moves the files over to the file server.
The hosting I’m using is provided by Namecheap and the server that it runs on can be accessed through cPanel. For security reasons the ftp:// protocol isn’t exposed (good!). According to their documentation, there’s 2 approaches to setting up an FTP client - FTPes or SFTP. I tried getting an SFTP workflow to trigger correctly but I was faced with error after error. I ended up deciding on using rsync over ssh whenever the main branch gets updated. Here’s what the final workflow file looks like. I’m likely going to add more steps in the future, depending on how the website develops but for now I am pretty happy with it.
name: Build and Deploy Jekyll Site
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
# Checkout the branch
- name: Checkout code
uses: actions/checkout@v3
# Set up Ruby environment
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3.5' # Specify the Ruby version required by Jekyll
# Install Jekyll and dependencies
- name: Install dependencies
run: |
gem install bundler
bundle install
# Build the Jekyll site
- name: Build Jekyll site
run: bundle exec jekyll build
# Upload the _site directory as an artifact
- name: Upload _site artifact
uses: actions/upload-artifact@v4
with:
name: jekyll-site
path: _site
deploy:
name: deploy
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download built site artifact
uses: actions/download-artifact@v4
with:
name: jekyll-site
path: _site
# Deploy to SFTP server using SSH
- name: rsync deployments
uses: burnett01/rsync-deployments@7.0.2
with:
switches: -avzr --delete
path: "_site/"
remote_path: "~/public_html/"
remote_host: $
remote_port: $
remote_user: $
remote_key: $