This blog is deliberately simple, but its deployment pipeline is very close to what you would use for a production-ready application.

Local Kubernetes on Proxmox

The blog runs on a local Kubernetes cluster that itself runs on a Proxmox hypervisor. The cluster nodes are virtual machines managed by Proxmox, which makes it easy to snapshot, back up, and resize the environment without touching the blog itself.

Inside the cluster, the blog is exposed through:

  • a Kubernetes Deployment for running the blog container
  • a Service to provide a stable, internal virtual IP for the pods
  • an Ingress resource to route external HTTP/HTTPS traffic to the Service

This is a standard pattern: Deployment → Service → Ingress.

Container Image

The site is built as a container image using a simple Dockerfile. The image:

  • installs Ruby and Jekyll
  • builds the static site into the _site directory at image build time
  • runs jekyll serve inside the container so that the blog is available over HTTP

Once the image is built locally, it is pushed to a private container registry that the Kubernetes cluster can reach. The Deployment is configured to pull this image by tag, so updating the blog is just:

  1. Edit the Markdown content.
  2. Rebuild and push the container image.
  3. Restart (or roll out) the Deployment so the new image is used.

Ingress, TLS, and DNS

The cluster runs an NGINX Ingress controller and uses cert-manager with Let’s Encrypt to provide TLS certificates automatically.

  • The Ingress resource defines the hostname for the blog.
  • cert-manager watches the Ingress and requests a certificate for that hostname.
  • Let’s Encrypt validates that the hostname points to the cluster and then issues a certificate.
  • NGINX terminates HTTPS and forwards plain HTTP traffic to the blog Service.

From the outside, it just looks like a normal HTTPS site, but all routing and TLS termination is handled inside the local Kubernetes cluster running on Proxmox.