New Hompage using Hugo and Forgejo
I'm running a small homepage and blog, primary as personal profile and self-marketing, but also to share my projects, experiences and learning. I want the homepage to be lightweight, fast and secure, and therefore I use a static site generator to render the contents. Since my homepage is primary my resume for self-marketing, I decided to go with careercanvas, created by Felipe Cordero, which is using the Hugo static site generator under the hood.
Since the carrercanvas is still work in progress, and doesn't work well with Hugo template projects, the best way at the moment is to fork Feilpes Homepage. I have done this, as a private repository on my self-hosted Forgejo instance. Since I also did some minor modifications of the carrercanvas theme, I also forked the carrercanvas.
To increase the comfort for updating the homepage, I created a Forgejo action, which is executed on my private Forgejo runner. This action looks like:
name: Build homepage container
on:
push:
tags:
- '*'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Default to bash
defaults:
run:
shell: bash
jobs:
# Build job
build:
runs-on: docker
env:
HUGO_VERSION: 0.147.3
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Hugo CLI
run: |
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&& dpkg -i ${{ runner.temp }}/hugo.deb
- name: Install Node.js dependencies
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
- name: Install podman
run: |
apt update
apt install -y podman
- name: Get date
id: date_step
run: echo "TAG=$(date '+%Y-%m-%d_%H-%M-%S')" >> $GITHUB_OUTPUT
- name: Show tag
run: echo ${{ steps.date_step.outputs.TAG }}
- name: Build homepage
run: |
npm install
rm -rf public
npm run build:css
npm run build
tar -czf "tomirgang-${{ steps.date_step.outputs.TAG }}.tar.gz" public/*
- name: Upload homepage artifact
uses: actions/upload-artifact@v3
with:
name: tomirgang.tar.gz
path: tomirgang-${{ steps.date_step.outputs.TAG }}.tar.gz
- name: Build container
run: |
podman build -t git.tomirgang.de/tom/tomirgang:latest .
- name: Build tag the container
run: |
podman tag git.tomirgang.de/tom/tomirgang:latest git.tomirgang.de/tom/tomirgang:${{ steps.date_step.outputs.TAG }}
podman image ls
- name: Upload latest container
run: |
podman push --creds tom:${{ secrets.HOMEPAGE_CONTAINER_TOKEN }} git.tomirgang.de/tom/tomirgang:latest docker://git.tomirgang.de/tom/tomirgang:latest
- name: Upload date-tagged container
run: |
podman push --creds tom:${{ secrets.HOMEPAGE_CONTAINER_TOKEN }} "git.tomirgang.de/tom/tomirgang:${{ steps.date_step.outputs.TAG }}" "docker://git.tomirgang.de/tom/tomirgang:${{ steps.date_step.outputs.TAG }}"
It is automatically execute when I create a new tag, and does the following high level steps:
- Prepare the fresh docker container with the dependencies. I use podman for building, since this works without issues and extended rights in a docker container.
- The artifacts are tagged with a date timestamp, which is prepared in the "get date" step.
- Then I run the hugo build in the "build homepage" step, which also creates a tarball of the generated files.
- Next the generated HTML tarball is uploaded to the action, for easy inspection.
- To deploy the homepage, I build a small nginx-base docker container which already includes the HTML, since this simplifies the deployment and update a lot. This container is build and published using the remaining steps.
The resulting container is provided using the container registry included in the Forgejo packages.
To serve the homepage, I use docker-compose.
services:
homepage:
image: git.tomirgang.de/tom/tomirgang:latest
container_name: homepage
ports:
- 2210:80
restart: unless-stopped
watchtower:
image: containrrr/watchtower
container_name: watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
command: --interval 3600
The homepage container is using the container image created by the Forgejo action, pulling it from Forgejo packages. The watchtower container is taking care of updating the image. This container checks once an hour for updates for all running containers, and pulls the image and restarts the container if an image is available.
Overall, this means, to do a change to my homepage, I edit the sources, or create the new blog post, and commit the changes to my repository. When I want to publish it, I create a new release in my repository, which will create a tag, and trigger the Forgejo action above. This action will build and publish the container, and in worst case one hour later watchtower will notice the new container and update it, which will make the homepage update available.
Fun fact is that the homepage, the Forgejo instance and the Forgejo runner are all hosted on the same server, which is just a Hetzner CX22 for about 5€ per month.
No Comments