Hakyll + sourcehut = ☺

This blog is now automatically deployed by pushing to its source repository at sourcehut! Here are the steps I took to convert it from a manual rsync to a job run by builds.sr.ht after each push to its git repository.

The first step is to create an SSH key so that the build service can access the filesystem on the VPS hosting my blog. Obviously we can’t use a passphrase since we need it to connect without any human intervention. Easy enough with the usual command:

desktop $ ssh-keygen -t ed25519 -f srht

Then to the secrets page on sourcehut and upload the content of the srht file (NOT srht.pub) as a new secret with the type ‘SSH Key’ and a reasonable description. We’ll need to make a note of the UUID that got assigned; for me, it was 2959238e-ea6f-4276-9441-cdc71b933f73.

The next step is to set up the user that we will connect as from the sourcehut builds service. We’ll also need to make sure the ownership and permissions on the webroot are properly set up.

server # WEBROOT=/srv/inv.alid.pw
server # adduser --system srht
server # chsh -s /bin/sh srht
server # chown -R srht:adm "$WEBROOT"
server # chmod -R ug=rwX,o=rX "$WEBROOT"
server # find $WEBROOT -type d -exec g+s {} +

I like to have files like this writable by an admin group so that I can delete stuff without having to be root myself, and the last command sets the setgid bit on all the directories so that newly-created files continue to belong to that group. That’s personal preference though: in the end, as long as the srht user can write there (and nowhere else) then everything should work just fine.

We’ll also need to authorise the SSH key we generated to log in as the srht user, and we can restrict it to only run rsync at the same time. Take the content of the srht.pub file we generated earlier, and add it to ~srht/.ssh/authorized_keys, along with the options to lock it down to rsync:

restrict,command="rrsync /srv/inv.alid.pw" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4E9kTv92l1NY1DgqXTnkHJWglVW+Laz6mQELviXzGI srht deployment

rrsync is not a typo: it’s a script that comes with the rsync package (in Ubuntu, it’s installed to /usr/share/doc/rsync/scripts/rrsync.gz, so you’ll have to decompress it and copy it somewhere that shows up in the srht user’s PATH) that means logging in with the given SSH key can only run rsync in the specified directory.

And that’s it for the server-side configuration! Now, we just have to fill in the .build.yml file to tell the sourcehut builders how to do all the deployment. Here it is, all in one go:

image: archlinux
  - stack
  - rsync
  - https://git.sr.ht/~jshholland/inv.alid.pw
  user: srht
  webhost: procyon.chrys.alid.pw
  hostkey: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKemAh9xHg0lQBhwzVp9UemuSgaDqVC5Mwa+CmnXijP8
  - 2959238e-ea6f-4276-9441-cdc71b933f73
  - build: |
      cd inv.alid.pw
      stack install
      $HOME/.local/bin/site build
  - deploy: |
      mkdir -p $HOME/.ssh
      echo "$webhost $hostkey" > $HOME/.ssh/known_hosts
      cd inv.alid.pw
      rsync -rlptzz --delete _site/ ${user}@${webhost}:

This ties everything together in two steps: first we compile the site binary that generates the website structure in _site, then, in the deploy task, we set up SSH and rsync the files into place. That’s it! We just have to save this into our repo and everything will just happen automagically when we push new commits.

One issue I have at the moment (and probably the reason I’m only finishing this now, when I first started trying to set this up back in November) is that it takes a long time for the build server to download and compile all the Haskell dependencies, particularly Pandoc. In the long term, a half-hour delay to publishing isn’t that bad, but it’s a little annoying. Next on my list is to try building this with NixOS (instead of Stack) to see if the binary caching provided there speeds things up a bit.