Back to the rack

How this site works

joe-martinez.com is served from four Raspberry Pis in a 10-inch rack at my place. Here is the path a visit takes, and how a change gets from my laptop to the cluster.

A visit

  1. Cloudflare

    Edge, outside my network

    DNS, HTTPS for visitors, and a cache in front of everything. If my homelab is down, Cloudflare still serves the last copy of the pages.

  2. Home router

    UniFi gateway

    Forwards HTTPS to the cluster's ingress address, handed out by MetalLB.

  3. Traefik

    Kubernetes ingress, on the Pis

    Routes by hostname, sends www to the bare domain, and terminates TLS with a Let's Encrypt certificate that cert-manager renews.

  4. nginx

    Two pods on different Pis

    One container image holding the whole site. A disruption budget keeps one pod up while the other restarts.

    1. The pages

      Static files

      Built with Astro. The 3D rack is three.js and only loads once it's on screen.

    2. Live status

      /api/status, cached 30 seconds

      nginx asks the rack-display status service, which keeps a summary of the cluster.

      1. Status service

        Node.js, rack-display

        Turns cluster state into the face on the rack's screen and a short public summary: node health, CPU, temperature and this site's uptime. No hostnames, IPs or app names leave it.

      2. Prometheus and Alertmanager

        kube-prometheus-stack

        Fed by node-exporter on each Pi, kube-state-metrics, PoE data from the UniFi switch, the NAS, and a probe that loads this site every minute.

A change

  1. git push

    github.com/0xJMart/resume-site

    Resume content lives in one YAML file. The page, the printable resume and the PDF all render from it.

  2. GitHub Actions

    CI

    Type-checks and builds the site, renders the PDF and preview images in a headless browser, and pushes an arm64 image to GitHub's container registry.

  3. Flux

    GitOps, in the cluster

    Spots the new image tag, commits it to my homelab repo, and applies it. Nothing is deployed by hand.

  4. Kubernetes

    k0s on four Raspberry Pi 5s

    Rolls the two pods one at a time.

  5. Uptime probe

    Blackbox exporter

    Loads the public URL every minute. If it fails, the rack's status face goes wide-eyed and the uptime figure on the front page drops.

The rest of the homelab runs the same way: Keycloak for single sign-on, Sealed Secrets, CloudNativePG, and an Unraid NAS for storage, all from one Git repository. Back to the rack.