Automating Jekyll deployments with Circle-CI

This will hopefully be quite a quick run through on how i deploy this website to my VPS using 3 services:

  • Visual Studio Code Server
  • Github
  • Circle-CI

Visual Studio Code Server

This is deployed on one of the servers in my house using Docker. Its a pretty simple one, here are the excerpt from my docker-compose that brings up almost all my home services:

version: "3.8"
  code_server: {}

    image: linuxserver/code-server:latest                               
    container_name: code-server                                         
    restart: unless-stopped                                             
      - PUID=1000                                                       
      - PGID=1000                                                       
      - TZ=Europe/London                                                
      - PASSWORD=${CODE_SERVER_PASSWORD} #optional                      
      - HASHED_PASSWORD= #optional                                      
      - SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD} #optional            
      - SUDO_PASSWORD_HASH= #optional                                   
      - PROXY_DOMAIN=${CODE_DOMAIN} #optional                           
      - DEFAULT_WORKSPACE=/config/workspace #optional                   
      - ./code-server:/config                                           
      - "traefik.http.routers.code-server.rule=Host(``)"
      - "traefik.http.routers.code-server.tls=true"                     
      - "traefik.http.routers.code-server.tls.certresolver=route53"     
      - "com.centurylinklabs.watchtower.enable=true"          

This doesnt include things like traefik, this is just the code-server section. If you need some help with traefik then id suggest checking out my post here: The Ultimate Monitoring Stack which also has an example of the traefik config im running.


Nothing really special here, standard private repo which i push changes to this website to. This is before jekyll has generated the site. The generation is done on Circle-CI.


This is where the interesting stuff is. When i set this up, i initially selected “Commit a starter CI Pipeline”. Here is my .circleci/config.yml

      - build:
              only: main
version: 2.1
      - image: cimg/ruby:2.7.4
    resource_class: medium
      BUNDLE_PATH: ~/repo/vendor/bundle
      - checkout
      - add_ssh_keys:
            - "xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
      - run: echo $REMOTE_HOSTKEY >> ~/.ssh/known_hosts
      - run: sudo apt-get update && sudo apt-get install rsync
      - restore_cache:
            - rubygems-v1-
            - rubygems-v1-fallback
      - run:
          name: Bundle Install
          command: bundle check || bundle install
      - save_cache:
          key: rubygems-v1-
            - vendor/bundle
      - run:
          name: Jekyll build
          command: bundle exec jekyll build
      - run:
          name: HTMLProofer tests
          command: |
            bundle exec htmlproofer ./_site \
              --allow-hash-href \
              --check-favicon  \
              --check-html \
      - persist_to_workspace:
          root: ./
            - _site
      - deploy:
          name: deploy
          command: |
            rsync -rlpgoDvc --no-o --no-g --no-perms /home/circleci/project/_site/ user@serverhostname:/dir/ectory/html/

This is almost ready to go we just need to amend a couple of things here:

resource_class : This is the size of instance used on CircleCI. I just used a medium instance as i saw no build time difference between using large instance and medium instance. So there is no point in wasting resources. Of course as you get more posts and data, that may change.

fingerprint : As we are using rsync to upload our generated site to our VPS, we need to be able to SSH into the target. For this i created a new keypair and put the private key on CircleCI and put the public key in my authorized_hosts. This section is adding that private key to the container we are using to generate our site.

$REMOTE_HOSTKEY : As always when we SSH into a new host we have confirm its the correct host. We are doing that automatically. To get the hostkey, we just need to run ssh-keyscan against the host we are uploading to and adding that as a new environment variable in CircleCI.

rsync command : Finally is the rsync command itself. It took a little while to get the correct options, but this way it completes without any warnings and gives us a successful build in CircleCI. Just add in your server details and correct path

This post should be the first which gets automatically posted to this website, hopefully if i have followed my own guide above, it should post within 3-4 minutes after pushing it to github!