Skip to main content

Building a self-hosted Tech Blog

Hi!

For the past few years, I have been working on private electronic projects. With growing knowledge from books and university, the concepts become increasingly complex - I need a way to cleanly document my process of making:

This is what I developed! (click to zoom)

Illustration showing the data flow
Figure 1: Illustration showing the data flow

My requirements of a blogging system
#

  • Low effort to write and publish - otherwise I won’t write
  • Runs on already rented VPS server to avoid additional cost & reuse domain
  • Lightweight and fast

Hugo as the core system
#

The core system is a static site generator called Hugo framework. It’s lightweight and generates fast and sleek websites. The visuals can be customized with a plethora of themes (This blog uses the blowfish theme).

  1. Write articles in Markdown format
  2. Preview website locally
    1. Execute hugo server in CLI
    2. Access web page under http://localhost:1313
  3. Deploy using Nginx Webserver.

Pro
#

  • You are in control (you build and serve the website yourself)
  • Markdown is used
  • The whole website is a “simple” folder
  • Use your own editor to write Markdown

Con
#

  • no on-website article editor for quick changes
  • pretty involved workflow, you will definitely need some hours to get up and running (I needed around 20-30 hours)

1. Step: Own Git server (using gitea)
#

To get the blog website, a bunch of build files collected in a directory is needed. The directory contains:

  • Articles in Markdown format
  • Images
  • Configuration files in TOML format
  • Themes
  • Dockerfile and docker-compose.yml

In addition, git adds versioning of your articles.

Now one could ask: Why do you need an OWN Git server? Because you need to store the photos somewhere! My blog, starting with two articles is already 350 MB in size!

2. Step: Webhook on Push
#

When committing a new article or change to my repo, I want the website to update. So I set up that a git push command will tell my portainer service!

3. Step: Container rebuild
#

Portainer is a service that manages docker containers. When a notification from git arrives, it pulls the repo and sets up a new nginx webserver:

Dockerfile

# 1. Get requirements
FROM hugomods/hugo:exts AS builder

# 2. Prepare workspace
WORKDIR /src
COPY . .

# 3. Clean up any broken submodule leftovers and clone fresh
RUN rm -rf themes/blowfish && \
    git clone --depth=1 https://github.com/nunocoracao/blowfish.git themes/blowfish

# 4. Build the site (Using -D for drafts and --gc for cleanup)
RUN hugo -D --gc

# 5: Serve the site with Nginx
FROM nginx:alpine
RUN rm -rf /usr/share/nginx/html/*
COPY --from=builder /src/public /usr/share/nginx/html
EXPOSE 80

docker-compose.yml for setting up the docker container stack

version: '3'

services:
  blog:
    build: .
    restart: always
    networks:
      - docker_website_network    # Join the specific network
    
networks:
  docker_website_network:
    external: true    # 'external' means "use the existing network, don't create a new one"

3.5 Step: SSL & Monitoring
#

For management of domains and subdomains, I set up the NGINX reverse proxy. It also helps manage certificates so that one can access the website via HTTPS.

Additionally, I want to know about how well my website performs! I chose Beszel, Dozzle and Umami to give me system stats, docker stats and website visitor stats. These services have their own dashboard which I locked away. Setting these up took me half a day.

4. Step: HTTPS
#

You can access the website! The website is simple, static, and loads fast.

Challenges
#

There were some significant challenges and questions to get this blog and running!

  • Before thinking about file storage size, I used a public git provider - however, they don’t allow much storage per repository - so I decided to spin up my own Gitea instance.

  • Gemini told me to use the LFS feature in git to more efficiently store images in repos. However, after I moved to my own git instance, I wanted to deactivate LFS for simplicity - this turned out to be NOT easy.

  • The CI/CD pipeline takes some time to get up. The webhook in step 2 is easy, but the automatic container build is not - also, if the container setup fails, you mostly get only error numbers, no detailed error logs.

  • Hugo recommends adding themes as git submodule. This turned out to be not compatible with the automatic build process of portainer

  • Use real name or pseudonym? At the end, I thought a real name would be cooler.

Hardware needed
#

This website is served using the lowest tier model of a rented Linux VPS (virtual private server) at 1blu.de:

  • 4 CPU cores
  • 8 GB Ram
  • 120 GB SSD

A VPS server means, that the resources are shared, but SSH and root access is provided. In my experience, this hardware tier model is enough to run a Minecraft server with at least 8 players, and an InfluxDB and Grafana dashboard service for my beehive monitoring too.

How to publish using my workflow
#

  1. Edit the local Hugo project by adding new article in Markdown
  2. Preview your articles locally in your browser
  3. Push changes to online git repo
  4. Wait for automatic update (around 30 seconds)
    1. My Git service informs the portainer docker container on my vps server
    2. Portainer pulls my git repo and rebuilds the whole stack
    3. The new stack contains only a simple nginx container with the new static website
  5. You can access the new article.

Conclusion: Should you also choose Hugo?
#

So if you are into DIY-server-management tasks, this is definitely for you. I don’t have any long-term experience with it yet, but I assume, it won’t be that maintenance-heavy. Since I already write a lot of notes with markdown and use git nonetheless, the workflow won’t be a problem for me.

But if you are not into these tasks, you should definitely choose a simpler alternative that doesn’t take so long to get up and running - in my case it took like 3 holidays in between university lectures! Maybe, there are services on the internet that manage hugo for you?

So let’s see - if there are more articles popping up, then this system works xD

I am interested in your thoughts! - Reply with a simple Email

Have a nice day,

Carl