Jon Allured

Computer Programmer, Whiskey Drinker, Comic Book Reader

Deploying Static Sites via CircleCI

published 04/24/21

Hosting static sites at DigitalOcean has been working out great for me but I wanted to make it even better so I've set them up to build and deploy at CircleCI on merges to the main branch. Here I'll outline how I do this.

Configuration Updates

My approach is to have a deploy job in the CircleCI config that sends the freshest build of my site to DigitalOcean. The formula for this operation is something like this:

  1. install rsync
  2. add ssh keys
  3. scan the DigitalOcean server for keys and update known hosts
  4. build the site using Middleman
  5. deploy the site using rsync

Here's an example of these steps:

  - run:
      name: Installing rsync
      command: sudo apt-get update && sudo apt-get install -y rsync

  - add_ssh_keys

  - run:
      name: Scan server keys
      command: touch ~/.ssh/known_hosts && ssh-keyscan >> ~/.ssh/known_hosts

  - checkout

  - restore_cache:
      name: Restore bundler cache
      key: bundler-v2-{{ checksum "Gemfile.lock" }}

  - run:
      name: Bundle install
      command: bundle install --jobs=4 --retry=3 --path vendor/bundle

  - run:
      name: Deploying site
      command: bundle exec rake deploy

See also my complete CircleCI config file for this site.

Setting Up SSH Keys

In order to safely allow CircleCI to deploy the site to DigitalOcean we have to generate and set some SSH keys. Start by creating a key pair like so:

$ ssh-keygen -m PEM -t rsa -C "jonallured-com@circleci" -f keys/circleci/jonallured-com

I do this in a ~/code/secrets folder on my machine and then check in these keys. This is an end-to-end encrypted git repo outside any particular project and I host it with Keybase.

Next up let's send the public key to our DigitalOcean server and update the authorized keys file there:

$ ssh-copy-id -i keys/circleci/ psylocke -f

Then upload the private key in the CircleCI interface:

Add SSH Key Screen in CircleCI Settings.

click for bigger

Make sure you add the ENV var at CircleCI too:

And that should correspond with the keyscan command in the yaml config so that the deploy doesn't hang on waiting for a yes/no answer on accepting the identity of the host.

Deploying The Site

I've got a rake task that builds and deploys the site:

desc 'Deploy site'
task :deploy do
  system 'middleman build --clean'
  system "rsync -av -e ssh --delete build/ #{ENV['DEPLOY_TARGET']}"

At this point our next steps will be to create a PR, get it merged to main and then our servers should be doing things automatically for us!