website/content/blog/gh_actions.md
Pagwin 17945a9af4 changed some properties on the gh pages article so it's the correct date and not a draft anymore
this commit has been amended to cause a redeploy because I'm lazy and I
fucked with some stuff
2022-01-26 20:29:46 -05:00

8.7 KiB

title description date draft
Setting up CD for this site How I setup Github actions to automatically update this site 2022-01-22 false

So recently I got a bit of a bee in my bonnet to go setup CD for this website. The main reasons that drove this were 1. deploying the site was mildly tedious which is a good enough reason on it's own and 2. I wanted to learn how to do it.

Wait but how did I find out about and how to do this?

I was aware of Github actions and a vague sense of how it should work observing how things went when I made my small contribution to Gerald. But observing that didn't really give a sense of how it worked. What did was when my friend Micha was working on implementing their own blog and set things up with Github actions to implement CI/CD. Then I saw this Fireship video which gave me a nice amount of context for this. Even with that bit of knowledge on how to setup stuff with Github actions I didn't really have a motivation to go do it.

The spark to actually do it

Then for a couple of reasons wanted to write a blog article about progress on Pogo. But I decided that before I wrote any more articles that I should go look into setting up CD for my site.

Implementing CD with Github actions

So with inspiration in my heart to go and do stuff with Github actions I began. First off I needed to set up the condition for my workflow running which was a pretty simple as I wasn't really doing anything interesting here.


on:

    push:

        branches:

            - master

The jobs

I knew due to reading some pages on Github's action market place and previous context that I would need to have at least 3 if not more steps

  1. checkout the code

  2. use Hugo to build the site

  3. deploy to my VPS

So going through each of those steps in order to see how I went about doing them first we have checking the code out which was a pretty simple uses: actions/checkout@v2 additionally telling it to fetch submodules due to the structure of my project. After checking out the code I had to use Hugo and conveniently there was a module for Hugo peaceiris/actions-hugo@v2 although sadly it only installs Hugo so another step would have to be added to build the app. But that step was a pretty simple run: hugo --minify. I will say though that if the example on the marketplace page didn't use the --minify option I wouldn't have either because I didn't know it existed so that was a nice little learning experience. After building the code I needed to deploy it which due to this being a static site was theoretically as simple as copying files with rsync. But I didn't want to have an automated action have access to root or my user for security and anti-stupidity reasons. To implement that I had to leave the realm of Github actions and go over to my VPS to set some stuff up.

Some work on the VPS

That stuff in question was adding a new user and changing the perms of /var/www/pagwin.xyz so that new user could edit files there. This was pretty simple.


sudo useradd website # I can hear people laughing at me already for not passing the -m option but relax I'll explain later

sudo chown -R website:www-data /var/www/pagwin.xyz # btw I didn't explain earlier but my website files are in /var/www/pagwin.xyz not /var/www/html because I'm hosting multiple sites on this VPS and the folder change makes it easier to keep track of which one I'm screwing with

However my unwillingness to have the new user have a home directory for cleanliness and to avoid unnecessarily leaving a user that could receive emails(I have an email server setup on this VPS as well) I didn't create a home directory. But in order for the deployment workflow on Github to deploy to the VPS via rsync it would need ssh access... Okay the problem may not be obvious if you don't understand ssh/good security practices very well. The problem is that in order to login to ssh via an ssh key you need to put that key into $user_home/.ssh/authorized_keys which requires the user have a home directory that I am unwilling to create. Password authentication is also not an option because allowing password auth on to a server is insecure compared to only allowing ssh keys. This is especially true when the ssh login is being done by an automated system. Also my VPS requires the usage of a TOTP if you login via a password and setting that up for Github actions sounds like a nightmare. Also also in order for the server to know the TOTP which requires a file... which goes into the home directory meaning nothing has changed or improved by trying to use a password.

Conveniently while $user_home/.ssh/authorized_keys is the default location for ssh public keys it's pretty easy to add another location for sshd to look for authorized_keys just by adding the line AuthorizedKeysFile .ssh/authorized_keys /etc/ssh/keys/%u.authorized.pub to /etc/ssh/sshd_config where the later bit of /etc/ssh/keys/%u.authorized.pub is added on from the default. That last bit of the config tells ssh to look for the public keys at an additional location where the username of the user trying to login replaces %u. After that whole hassle is done with generating the ssh key is pretty simple with ssh-keygen and putting the public key in the right spot. Adding the private key as a Github secret was annoying however but I'll discuss that in the #Dealing With My Stupidity section.

What were we talking about oh yeah Github actions

anyways yeah this is what I initially(spoiler I change it) wrote for Github actions to go and deploy the app.


uses: up9cloud/action-rsync@master

env:

  HOST: pagwin.xyz

  KEY: ${{secrets.SSH_KEY}}

  TARGET: /var/www/pagwin.xyz/

With that I saved the file to .github/website-publish.yml and felt a mild sense of accomplishment. In hindsight that sense and first file are hilarious and while I would love to immediately explain why first I want to take a second to show a step I added after I finished dealing with my stupidity. That step is a cleanup step that deletes the old site before copying over the new one so people can't snoop around in redundant files. I implemented that with this tidbit.


uses: appleboy/ssh-action@master

with:

  host: pagwin.xyz

  username: website

  key: ${{secrets.SSH_KEY}}

  script: rm -rf /var/www/pagwin.xyz/*

Dealing With My Stupidity(and a private ssh key)

The obvious act of stupidity if you paid attention to what I wrote is that I saved the file to .github/website-publish.yml instead of .github/workflows/website-publish.yml. Fixing that was pretty easy when I figured out what was going on. After that I then had to tweak the deploy step a bit to make rsync work properly. I did a couple of things wrong with the deploy step, one I didn't specify a username, and two I didn't specify my source directory. The source directory thing was particularly stupid as I wanted the files inside the public folder but just putting ./public gave the folder itself with the files in it. As I removed that from my vps I deleted the /var/www/pagwin.xyz folder which required a brief recreation of that folder. Then I setup the source correctly to get the files properly but also set the target wrong so everything would go in a folder * which was annoying but at the end of all that I had a pretty smooth setup.

Conclusion

Overall I'm very happy I did this because it gave me a nice bit of practical understanding of how to set up Github actions for future projects. I hope reading about my technical spaghetti VPS and idiocy wasn't too boring. Oh yeah for those who care this is what the yaml file looked like in the end


name: Website publish



on:

  push:

    branches:

      - master



jobs:

  build:

    runs-on: ubuntu-latest

    steps:

      - name: Code Checkout

        uses: actions/checkout@v2

        with:

          submodules: true

          fetch-depth: 0

      - name: Hugo Setup

        uses: peaceiris/actions-hugo@v2

        with:

          hugo-version: '0.91.2'

      - name: Build

        run: hugo --minify

      - name: Clean

        uses: appleboy/ssh-action@master

        with:

          host: pagwin.xyz

          username: website

          key: ${{secrets.SSH_KEY}}

          script: rm -rf /var/www/pagwin.xyz/*

      - name: Deploy

        uses: up9cloud/action-rsync@master

        env:

          HOST: pagwin.xyz

          USER: website

          KEY: ${{secrets.SSH_KEY}}

          SOURCE: ./public/*

          TARGET: /var/www/pagwin.xyz/