How to configure your Jekyll Repository for CI with GitLab

TLDR;

This is the .gitlab-ci.yml I am using:

image: ruby:3.1

cache:
  paths:
  - vendor/
  
pages:
  stage: build
  script:
    - bundle install --path vendor
    - bundle exec jekyll build -d public
  artifacts:
    paths:
    - public
  only:
  - main

rsync:
  stage: deploy
  # using ubuntu:18.04 in order to support old host key algo
  image: ubuntu:18.04
  before_script:
    - apt-get update -yqq
    - apt-get install -yqq openssh-client rsync
  script:
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-keyscan -H box.zechendorf.com >> ~/.ssh/known_hosts
    - rsync -av public/ root@box.zechendorf.com:/home/user-data/www/default
  only:
  - main

The task: Automatically deploy your Jekyll site with GitLab to a mailinabox server

I run this static website on a mailinabox server - I also host the repository on a self-hosted GitLab instance. So it seemed logical to configure GitLab to automatically deploy the website when changes are being pushed to the main branch.

GitLab uses a .gitlab-ci.yml file in the repository root to configure continuous integration.

Two Stages: Build and deploy

Stage 1: Build

We initialize the .gitlab-ci.yml file with the following contentL

image: ruby:3.1

cache:
  paths:
  - vendor/
  
pages:
  stage: build
  script:
    - bundle install --path vendor
    - bundle exec jekyll build -d public
  artifacts:
    paths:
    - public
  only:
  - main

This will spin up a ruby:3.1 image (and cache the vendor subfolder). We then define pages for the build stage. It will install jekyll and execute it to build the static files into a folder public. This will also generate an artifact that can later be downloaded in GitLab. With only main we restrict this to the main branch.

Stage 2: Deploy

This is where I spent the most time, since my mailinabox is still ubuntu 18.04 (and thus uses old host key algorithms which were incompatible with newer docker images).

To achieve successfull deployment we add the following lines to the .gitlab-ci.yml.

rsync:
  stage: deploy
  # using ubuntu:18.04 in order to support old host key algo
  image: ubuntu:18.04
  before_script:
    - apt-get update -yqq
    - apt-get install -yqq openssh-client rsync
  script:
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-keyscan -H box.zechendorf.com >> ~/.ssh/known_hosts
    - rsync -av public/ root@box.zechendorf.com:/home/user-data/www/default
  only:
  - main

This will spin up an ubuntu 18.04 image, install openssh-client and rsync (needed to sync the files).

It will then store the GitLab variable $SSH_PRIVATE_KEY (you can set this in Settings/CI/CD) and set the correct access rights, so that it can safely connect to the server via SSH and public/private key authentication.

It will additionally save the host key for the target host (so the rsync works) and rsyncs the public folder to root@box.zechendorf.com:/home/user-data/www/default.

In order for this to work for you, you need to adapt box.zechendorf.com to your target machine and probably change the /home/user-data/www/default according to your needs.

The result

Every time I push changes to the main branch in the repository, a GitLab runner will build the static website and deploy it to the desired folder at my mailinabox server.