Site CI/CD
Whenever I write a new article for my site, I would like to have it published automatically. As mentioned earlier, I’m using Hugo to generate it and I have seen several solutions of other Hugo users for automated deployment.
The Hugo documentation refers to several online services like Wercker, Netlify and GitLab.
The documentation also mentions GitHub, but those instructions have not been updated to use GitHub Actions. GitHub has numerous Actions to support Hugo site generation and deployment.
Other users have set up other creative solutions to automate their site deployment. Ryan Himmelwright decided to use Jenkins, while Sean Gransee used CircleCI and Chris Ferdinandi set up a webhook on a Digital Ocean server. I’m self-hosting my site and my Git server. Hosting my own Jenkins server as well, feels overdone.
Instead, I considered using Git Hooks to update my site after pushing new content to the repository. That would have worked nicely, if I wasn’t running Gitea in a container. I didn’t want to modify the image to include the required Hugo executable, so I had to find another way. Gitea also supports using webhooks which allows accessing resources outside Gitea’s container. This post describes how I used webhooks to deploy my Hugo based sites.
Toolchain
The workflow is implemented using the following chain of tools:
After writing my post, I commit it and push it to my Gitea Git server. Gitea is then calling an end-point which is implemented using webhook. webhook makes it very easy to define the end-point and have an application executed. It is calling a bash-script that is checking out the latest changes on Gitea, is then building the site using Hugo and is finally copying the result to the webroot of the site.
Gitea webhook configuration
Gitea has many configuration options to set up a webhook:
In my case, I want to post some information about the push, when it was pushed. Using the secret, the end-point can be secured.
webhook configuration
webhook allows to define many end-points using a JSON formatted config file:
/etc/webhook.conf
[
{
"id": "gitea",
"execute-command": "/home/bas/dockerfiles/caddy2/deploy_site.sh",
"pass-arguments-to-command":
[
{
"source": "payload",
"name": "repository.ssh_url"
},
{
"source": "payload",
"name": "repository.name"
}
],
"trigger-rule":
{
"and":
[
{
"match":
{
"type": "value",
"value": "<secret text>",
"parameter":
{
"source": "payload",
"name": "secret"
}
}
}
]
}
}
]
End-point fields:
- id: the name of the end-point; is the last part of the path on the server:
http://<server>:3000/hooks/gitea
- execute-command: absolute path to script or executable on the filesystem to be executed when the end-point is hit and the trigger rules are met
- pass-arguments-to-command: specifies the arguments to pass to the command, where the source
payload
refers to the JSON posted to the end-point and thename
to the field in it to be used.repository.ssh_url
would refer to the URL on which to access the Git repository to which an update was pushed to.
See the webhook project for more detailed information.
Deploy script
#!/usr/bin/env bash
REPOSITORY_SSH_URL=$1
REPOSITORY_NAME=$2
WORKDIR=/var/tmp
SITEDIR=/home/bas/sites
pushd $WORKDIR
rm -rf $REPOSITORY_NAME
git clone $REPOSITORY_SSH_URL $REPOSITORY_NAME
docker pull klakegg/hugo:latest-ext
docker run --rm klakegg/hugo:latest-ext version
docker run --rm -v $WORKDIR/$REPOSITORY_NAME:/src klakegg/hugo:latest-ext --gc --minify
rm -rf $SITEDIR/$REPOSITORY_NAME
mkdir -p $SITEDIR/$REPOSITORY_NAME
cp -r $WORKDIR/$REPOSITORY_NAME/public/* $SITEDIR/$REPOSITORY_NAME
popd
First a temporary working directory is deleted. Then I clone the repository to build from. The latest klakegg/hugo image is pulled and then used to generate the site. Finally, the generated site directory is replaced by the newly generated site files and the work is done.
This script is generic and can deploy any Hugo site as long as the repository.ssh_url
and repository.name
are passed as
arguments. This makes it easy to use a single webhook end-point and deploy script to refresh multiple Hugo sites.
Conclusion
This relatively simple set of tools and scripts really work well for me. Push and forget!
October 19, 2020