Previous page

Automate blog deployment via Github Actions

As my blog is mostly a static website running via Hugo, I always thought that bothering with setting some automated workflow to deploy it is a rather pointless task

Step 1 - Prepare the server - how to login from agent

As I wanted to have an automated deployment via external Github agent, I had to provide it access to my server. For this purpose I created a separate account, which only has access to add/edit content within my nginx blog directory.

Afterwards it was time for proper authorization method - provide of new SSH keys via ssh-keygen method. For purpose of this blog post let’s say I used the default values for everything - id_rsa.pub public Key and id_rsa private key located in my ~/.ssh directory. As this key was supposed to access the server on which blog is hosted, public key was added to ~/.ssh/authorized_keys on newly created user account.

Then it was time to provide proper configuration to Github. As I planned to use shimataro/ssh-key-action action for SSH configuration, there were few steps I had to to:

  1. Add public key to Deploy keys settings in a project
  2. Add private key to Secrets settings in a project
  3. Add known_hosts content to Secrets settings in a project
  4. Add config content to Secrets settings in a project

While first two are pretty obvious for anyone who ever used SSH, known_hosts and config may be a little big surprising.

known_hosts are responsible for having list of all hosts that we agreed to access ourselves. If you will go to your /.ssh/ directory on any machine where you used SSH to connect to other hosts (i.e. for git purpose), you will find that file there. It will contain informations about all machines to which you connected via ssh. If there is no entry when you are connecting to new host in know_hosts, SSH will ask you if you are sure you want to connect to it. For Github actions process should be automated, so we should not get any prompts during agent workflow actions. That’s why part of my known_hosts that has info about my deployment server has been added as another config option to my Secrets.

Last but not least, config file. config in SSH is pretty handy feature which can be used i.e. for preparing pre-set environments. For example, instead of typing ssh username@hostname.example.com -p 3999 each time you want to connect to the server, I can provide following in config file:

Host myhost
        HostName hostname.example.com
        Port 3999
        User username

And just use ssh myhost to connect to this server. This allows to make whole SSH connection part in definition file much simpler, and helps with hiding the connection details from people who can read the repository code.

Step 2 - GitHub Actions!

After preparation, this part is pretty simple. My whole workflow for deployment was always to connect via SSH to the server, git pull latest changes from repo and run hugo command, which already has proper publish directory pointed within hugo config.toml file.

So basically all I had to do was access the server, get to the repository direction (lets call it ~/blog/), run git pull and follow it via hugo command. I can even chain it all into a single command like this:

ssh myhost 'cd blog && git pull && hugo'

So now, moving it into a proper Github action pipeline, we receive something like this:

name: Blog CI
on:
  push:
    branches: [ "master" ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Install SSH Key
        uses: shimataro/ssh-key-action@v2.3.1
        with:
          key: ${{ secrets.PRIVATE_KEY }}  
          config: ${{ secrets.CONFIG }}
          known_hosts: ${{ secrets.KNOWN_HOSTS }}
      
      - name: Refresh content
        run: ssh myhost 'cd blog && git pull && hugo'

And just like that, after each push to master branch, latest content is almost immediately available on this blog.

With this post I am almost able to achieve my one-per-year trend on new posts. Hopefully I will be able to write more of them in upcoming time, as I recently realized that this blog is mostly helping me recall all the tricks from my toolset, which after some time are forgotten. Or, as it was case few weeks ago - my carefully prepared snippets were left within repositories of company that I have left, and suddenly I lost access to them. So for this purpose, I think it it better to write them down in place such as this. If this comes handy for other people in a future - good for you! But starting from now, I am treating this blog mostly as my private notebook for all sneaky little tricks. Expect more of them soon.

 

Previous page