Skip to main content
From Hashnode to Kubernetes: Why I'm Self-Hosting My Blog Like a Bank Website

From Hashnode to Kubernetes: Why I'm Self-Hosting My Blog Like a Bank Website

Andrei Vasiliu
Author
Andrei Vasiliu
Romanian expat in Italy. Platform Engineer by trade, homelab builder by passion. Documenting every step of building enterprise-grade infrastructure at home.
Table of Contents
Self-Hosting the Blog - This article is part of a series.
Part 1: This Article

The Question That Changed Everything
#

Over the past months, I’ve received a variation of the same question more than any other:

“I know tool X, Y, and Z… I’ve done courses on tool Q… but I can never find documentation on how you actually put all these tools together in production.”

It’s a fair point. The internet is full of isolated tutorials: “How to set up Argo CD,” “How to write a Dockerfile,” “How to configure Helm charts.” But almost nobody shows you how the entire assembly line works end-to-end… from a developer pushing code to a user hitting a URL in their browser.

In my day job, architecting platforms for private banking, I build exactly these pipelines. But showing a bank’s internal CI/CD pipeline isn’t exactly an option. So I needed a real, public application to demonstrate the full lifecycle.

That application is this blog.

Why I Left Hashnode
#

If you’re reading this, you may have already noticed: this blog is no longer on Hashnode. You’re looking at a Hugo-powered site.

Let me be clear: Hashnode is a great platform. It served me well when I started this journey and wanted to focus purely on writing. But after a recent update, a feature I relied on heavily was removed: the ability to sync blog posts to a GitHub repository automatically. Every time I published, my Git repo would get updated with the new Markdown file. It was a clean, version-controlled workflow that felt right for an engineer.

Without that sync, the workflow feels broken. And rather than fight it, I saw an opportunity.

I have a fully operational platform sitting in my homelab. We’ve built a networking layer with automated TLS, distributed storage with Longhorn, a PostgreSQL database layer with CloudNativePG, centralized identity with Keycloak, and a battle-tested GitOps workflow with Argo CD. Why not use it?

The Interim Setup: Hugo on Netlify
#

Of course, before I can host the blog on Kubernetes, I still need a place to… write about hosting the blog on Kubernetes. It’s a chicken-and-egg problem.

So for now, the blog is running on Hugo and hosted on Netlify. It’s a clean, fast, and reliable setup that lets me keep publishing while I build out the full self-hosted infrastructure. Think of Netlify as the scaffolding… it keeps the building standing while we renovate the foundation underneath.

The Mission: Treat It Like a Bank Website
#

This isn’t just about hosting a blog. This is about using a real, public-facing application as a living case study for how a production website is built, deployed, and operated… the same way I’d do it for a financial institution.

Think about it. A public-facing website is the most relatable production workload there is. Everyone understands what a website does. It needs to be fast, secure, always available, and properly monitored. It has a CI/CD pipeline, a container image, DNS, TLS, logging, and analytics. It is, in miniature, every problem a platform engineer solves daily.

The Public Test Repository
#

To make this series truly reproducible, I’ll create a public GitHub repository with a test website built using the exact same technology stack as this blog — Hugo, the same containerization approach, the same pipeline, the same Helm charts. Every piece of infrastructure I build for that test site will be a 1:1 mirror of what powers andreivasiliu.com.

This means you won’t just be reading about concepts… you’ll be able to clone the repo, follow along, and deploy the same setup yourself. And since the technologies are identical, once the full Kubernetes pipeline is functional for the test site, switching this blog over is a simple configuration change.

Every step I take will be documented in its own blog post, turning this migration into a multi-part series. Here is the roadmap:

Phase 1: Containerization & CI/CD
#

The first step is to take the blog’s source code and make it deployable.

  • Containerize the blog: Write an optimized, multi-stage Dockerfile to package the static site generator into a lean, production-ready container image. No bloated base images, no unnecessary packages… just like we’d ship a production artifact at work.
  • Build a GitHub Actions pipeline: Create a CI pipeline that automatically builds the container image on every push to main, including container image scanning for CVEs before pushing and multi-architecture builds (amd64/arm64) for flexibility.
  • Implement automatic semantic versioning: Build a custom GitHub Action that versions the container image automatically (e.g., v1.2.3) based on commit conventions, eliminating the need for manual tagging. This is a pattern I use extensively in enterprise pipelines.
  • Push to a container registry: Configure the pipeline to push the versioned image to a container registry with proper image tagging and retention policies — the same way we manage artifacts in a regulated environment.

Phase 2: Kubernetes Deployment with GitOps
#

With a container image ready, we bring it into the cluster using the patterns we’ve already established.

  • Create Helm charts: Build a Helm chart for the blog deployment — configurable replicas, resource limits, health checks, and environment-specific overrides… following the same patterns from the base manifests repository in my four-repo GitOps structure.
  • Deploy via Argo CD: Define the Argo CD Application manifest and let GitOps handle the rollout. The pipeline will automatically update the image tag in the environments repository, triggering a seamless deployment. No kubectl apply here.
  • Expose via Gateway API: Serve the blog over HTTPS using Traefik and the Gateway API, with certificates automatically managed by cert-manager and Let’s Encrypt.

Phase 3: Observability & Production Hardening
#

A production website isn’t just deployed; it’s observed.

  • Analytics collection: Show how website analytics are collected… tracking visits, page views, and reader behavior without relying on third-party SaaS tools, respecting user privacy.
  • Centralized logging: Demonstrate how application logs are collected, aggregated, and made searchable, so that when something breaks at 2 AM, you know exactly where to look.
  • Crash and error reporting: Set up proper error tracking to capture frontend and backend exceptions, so issues are surfaced before users report them.
  • And more: Health checks, resource limits, network policies, uptime monitoring… all the small details that separate a “hobby deployment” from a production one.

What We’ve Already Built
#

This plan isn’t starting from zero. Look at what we’ve assembled over this series:

Think of it this way: we’ve spent months building a Formula 1 car piece by piece. The engine (Kubernetes on Talos), the chassis (the four-repo GitOps structure), the aerodynamics (Cilium networking), the fuel system (secrets management with 1Password), the tires (TLS with cert-manager), and the cockpit (Keycloak identity).

Now it’s time to drive it.

What’s Next
#

In the next post, we’ll get our hands dirty with Phase 1: containerizing the blog and building the CI/CD pipeline from scratch. We’ll write the Dockerfile, set up GitHub Actions, and implement automatic versioning — a complete, production-grade build pipeline.

If you’ve ever wondered how all the individual pieces of a modern DevOps stack come together to ship real software, this series is for you. Follow along, and let’s build something real.

As always, all code and configurations will be open source and available in my GitHub repositories.


This is a continuation of my homelab series. If you’re just joining, I recommend starting with Why Not a Homelab? and following the series from the beginning.

Self-Hosting the Blog - This article is part of a series.
Part 1: This Article