Essay · · 2 min
Keeping It Simple: Automating Hugo with Gitea
Rebuilding a website by hand after every post gets old fast. I already keep my git repos on a self-hosted Gitea server, and this site is plain Hugo, so the obvious move was to make a push to main rebuild the site on its own.
Hooks or Actions?
My first idea was a post-receive hook, a shell script Gitea runs after every push. It would work, but the script lives inside Gitea’s data volume, which is exactly where I’d forget it exists. Gitea Actions does the same job with the workflow checked into the repo right next to the posts. If it breaks, the fix is a commit like any other.
The workflow
It lives at .gitea/workflows/build.yml:
name: Build Hugo Site
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
container:
image: ghcr.io/catthehacker/ubuntu:js-latest
volumes:
- /home/john/mine/scripts/hugo/public:/mnt/hugo_output
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: true
- name: Install Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: '0.167.0'
extended: true
- name: Build Hugo Site
run: hugo --minify --buildFuture --destination /tmp/site
- name: Publish
run: |
test -s /tmp/site/index.html
find /mnt/hugo_output -mindepth 1 -delete
cp -a /tmp/site/. /mnt/hugo_output/The runner checks out the repo (the theme comes along as a git submodule), installs Hugo, builds the site in a scratch folder and copies it into the folder nginx serves. Publishing a post is now: write Markdown, commit, push. A few seconds later it’s live.
Update, October 2026
The version I first posted here emptied the live folder and then built straight into it. If the build failed, the site was simply gone until the next good push. It also passed --buildDrafts, so anything I’d marked as a draft got published anyway. Neither bit me for a year and a half, which is the problem with things that work.
The workflow above builds somewhere else first and only touches the live site once the build succeeds. That got tested on day one (Hugo had dropped a front matter key I was still using), and the old site stayed up while I fixed it. It also pins the Hugo version, so an upgrade happens when I choose it instead of whenever a release lands. Still two tools and one YAML file. It just fails the right way now.