Building a blog using Hugo, MinIO, and Woodpecker CI

Bluemedia (Oliver) | Jan 28, 2024 min read


If you’re reading this post, you’ve just landed on my brand-new personal blog. Welcome! This site marks the evolution from my previous WordPress instance, representing a project I’ve been wanting to do for a long time.

Since 2018, I’ve maintained a blog based on the WordPress platform. However, for nearly as long, I’ve wanted a more customizable and less maintenance-intensive alternative. My former blog was essentially an off-the-shelf theme, minimally personalized with generic stock photos. Customization was confined to a few UI elements, and the dynamic nature of WordPress resulted in a relatively high level of maintenance (including the database, web server with PHP, plugins for email delivery, and more complex UI elements).

In 2021, with the registration of my domain,, I aimed to create a personal website where I could showcase not only myself but also my projects and experiences. I strived for a clean, user-friendly, and fast UI that I could customize according to my preferences and host without significant technical overhead. Due to various other projects and a lack of motivation to produce new blog posts, this idea lingered for two years before I finally revisited and brought it to life.


Given my limited satisfaction with WordPress, I embarked on the quest for new tools to build my new site. Right from the start, it was clear to me that I wanted to construct the new site using a static site generator. Since I already use Hugo for the homepage of my DN42 network and find working with it quite enjoyable, the choice was quickly made.

What is a Static Site Generator?

There are fundamentally different ways to deploy a website. In most cases, websites are dynamically generated upon request. This involves loading content from a database through a programming language (e.g., PHP) and rendering it into finished HTML using a template or layout, which is then delivered to the browser. This is how most CMS systems, including WordPress, operate. One advantage of this approach is the ability to dynamically customize pages with many features. However, the drawbacks include the need for specific backend hosting requirements and the relatively slow and computationally intensive regeneration without caching.

Another option is to hand-code a site directly in HTML and CSS. The finished code is then delivered as a bundle of static files by a web server. Since no content needs to be dynamically loaded and generated, this approach is significantly faster and less computationally intensive. Yet, creating an entire site from scratch is complex, time-consuming, and impractical if you want to quickly publish new blog posts.

A static site generator combines many advantages of the two mentioned approaches. Typically, there is a pre-built theme or layout consisting of HTML and CSS with various placeholders for the actual content. The content is then usually represented in separate files along with metadata such as titles, links to images, etc. Markdown is often used for formatting and text layout, as is the case with Hugo.

Because the entire project is structured as a folder with files, it can be easily incorporated into version control systems like Git. This allows for convenient editing and saving, complete with version history. The actual static site generator is a program that reads both the layout/theme and content, combining them into finished HTML and CSS files. These can then be delivered directly via a web server. Since data generation occurs only once, instead of with every page request, the site is faster and operates without additional dependencies. Furthermore, only the knowledge of HTML, CSS and the templating language of the generator is required for customizations.

Automated Build and Deployment of a Hugo-Based Site

I’m all about automating stuff and letting the system take care of the repetitive tasks for me. When making changes to a Hugo-based site, the usual process involves making the actual modification, running Hugo to generate the code, and subsequently uploading it to a web server. I’ve streamlined this workflow for my convenience.

In addition to my blog, I manage a variety of other services (for a glimpse, you can check out my status page). To simplify maintenance and save time, some of these services include infrastructure components like Forgejo (Git hosting), Woodpecker CI, and a MinIO instance (S3-compatible object storage). Since I already operate these services, it makes sense to leverage them for the blog as well.

The source code resides in Forgejo (publicly accessible here), and with every change to the main branch or at least once a month, the final site is generated through a Woodpecker CI pipeline. The data is then uploaded from the pipeline to a MinIO bucket. The Nginx web server behind now acts as a simple reverse proxy for the MinIO bucket, handling a few additional rewrites so that you don’t have to specify index.html in the URL of each page. The shortened configuration looks something like this:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;


    location / {
        rewrite ^(.*)/$ $1/index.html break;
        rewrite ^(.*/[^./]+)$ $1/index.html break;

        proxy_http_version 1.1;
        proxy_connect_timeout 300;
        chunked_transfer_encoding off;

        proxy_intercept_errors on;
        error_page 404 =404 /404.html;

        proxy_set_header Host "";
        proxy_set_header Connection "";


So, for making changes, all it takes is a simple git push, and within a few minutes, the update is live.

Layout and Design

The theme I’m using is a fork of “Hugo Profile” by Guru Sabarish. I’ve made some layout adjustments and changes to the design colors, along with replacing the default font with Atkinson Hyperlegible. Atkinson Hyperlegible is an open font specially developed by the Braille Institute of America to ensure readability for individuals with visual impairments. If you’re interested in the changes I’ve made, you can find my fork on GitHub.


With my new blog, I finally have a modern and lightweight way to showcase myself and my projects. Now that I’m much happier with the overall look, I plan to publish more posts in the future. So stay tuned for new content!