Intro

A few weeks ago, I realized that while I’m good at ideation, problem solving, system design, and building what I need. I usually default to hosting-providers for everything I deploy over the web. There was a serious DevOps gap in my toolbox, especially with Kubernetes. This was more apparent when I attended Web Summit Vancouver 2026 and chatted with my buddies working as DevOps engineers.

Did some good old fashioned research (I’m talking 17 tabs in a Zen folder called ‘Learning Kube’) and got to work!

My Docs

I learned a ton about setting up a VPS and Kubernetes and organized all of it into the following docs:

Initial Setup

I got a cheap VPS from Hetzner with more RAM than I can actually afford.
I opted for a simple LTS version of Ubuntu Server, then completed basic configuration by:

  • Setting up SSH
  • Creating a non-root admin account
  • Configured firewall with UFW and locked certain ports…
  • Set up DNS and configured the routing table
  • Issued SSL certificates

Then the machine was ready for some fun. I installed Git, Docker, and Kubernetes.
I picked K3S, because it’s a single node, single cluster distribution with some nice quality-of-life right outta the box. Traefik, the reverse-proxy and load-balancer is such a blessing, more on that later…

Check You Have An IPv4 Address!

Before installing K3S, I had to adjust my routing table and give my server an IPv4 IP address, because my default Hetzner only issues IPv6 and that was throwing errors left and right when trying to use networking features and commands like curl!

K3S

Once K3S is installed and set up, I began by organizing a directory for manifest files, per namespace, project, etc. Set the whole thing to live in a Git repo so I can track my manifest versions.
While kubectl lets you roll back deployments and changes, I prefer having a history.

To test things out, I deployed a non-functional frontend I made with astro a while back. Doing so really drove home the main concepts for Kubernetes.
Namely:

  • Deployments
  • Services
  • Ingress
    The client is accessible at arc.aabuharrus.dev but doesn’t do anything (Thanks, Spotify 🙃) but was a good test-dummy.

Full Stack - multiple services

To understand how cluster networking works, I decided to deploy a Full Stack app I had built for a close friend, this one’s personal so I won’t be sharing it…
But here are the layers:

  • Dead simple React + Vite (TypeScript) client
  • Supabase authentication
  • PostgreSQL database
  • Flask API server
    With the exception of the auth service, everything else had to be updated, containerized using docker, and deployed it onto my cluster.

When I built this, the data was also on Supabase since they offer very good value PostgreSQL db with all the goodies attached on the free-tier.
To deploy it onto my cluster, I used Helm. Which is basically a package-manager for Kubernetes. It also uses YAML files but calls them “Charts” and are much bigger than manifests. Installation and migration was simple.

While the database was deployed under a separate namespace for Persistent Storage Volumes, the rest was under the project’s namespace. This made networking, admin, and CI/CD simpler. The command kubectl get all -n <namespace> might as well get its own alias…

Admittedly, containerizing the client app was a chore, due to the fact each container needed an Nginx web server inside to serve the compiled JS files but injecting the secrets from K3S was a full evening of debugging.
Whereas the Flask server was already containerized and just needed refactoring for Postgres.

The flow for all of these layers is like follows:

  1. Write and apply deployment manifest
  2. Write and apply service manifest
  3. Write and apply secrets
  4. Write and apply ingress manifest (where needed)
    Check health, debug, repeat…

Traefik

I mentioned Traefik being K3S’ default reverse-proxy, it’s a treat because it also handles issuing TLS certificates using Let’s Encrypt without needing to install cert-manager (I believe it’s included under the hood).
All I needed to do was configure DNS records in my registrar’s settings, ensure the ingress manifests were correct, and all port mappings for services and the Dockerfiles were correct.
// This sold me on K3S for personal use!

Grafana & Victoria Metrics

What’s a DevOps journey with metrics and dashboards to display them? Nothing.
Again, I turned to Helm, installed the correct charts I needed for Grafana and Victoria Metrics. Some set up, ingress, DNS, et voilà!
My Grafana dashboard was showing readings from my cluster.

Under the hood, Victoria Metrics uses a Prometheus compatible service to scrub and store the data into its own persistent volume, and in turn streams it to Grafana.
There remains quite a bit of tweaking I’d like to do with this dashboard and get better familiarized with Grafana, but it’s fine for now.

Web Server

I also plan on running some daemons and other services like Python scripts, Rust crates, and what have you outside the K3S cluster. These won’t be able to communicate with the wider internet without a web server. This is where Nginx and Apache server fit in.
Run them, configure them, and they’ll route the traffic.

What’s The Plan?

You’re probably asking, so what’s it running besides that? Personal projects, mainly things I personally built for me and friends, self-hosted apps, etc. Nothing for public use.
Ultimately, I am doing this to learn and grow my skills.
So far, it’s done that. I’ve learned a great more deal about:

  • Kubernetes
  • Linux Servers (I’ve only used it on my PCs before. arch, btw)
  • Networking
  • CI/CD
    However, I’ve a few projects and ideas I plan on building and now I’ve a mostly ready server and Kubernetes cluster ready to house them. : )