Copyright © KC Green

GitOps

From Mastodon to snac: A Lighter Fediverse Stack

 infrastructure 

Why the lab dropped PostgreSQL, Redis, and object storage for a filesystem-backed snac instance — with VolSync restic backups.

The lab used to run Mastodon on Kubernetes: PostgreSQL, a Redis-compatible cache, and S3-shaped media storage on top of the usual edge stack. That worked, but it was heavy for a small personal instance — more moving parts than the workload justified.

The fediverse home at this-is-fine.social now runs snac instead: a minimal ActivityPub server in portable C, no database, all state on a single filesystem tree, backed up off-cluster with the same VolSync + restic pattern as other stateful apps.

Pocket ID as the Lab OIDC Provider (Zot Example)

 infrastructure 

A small IdP at auth.this-is-fine.io — native OpenID login for the Zot registry.

Pocket ID is a small OpenID Connect provider — enough for a homelab without Keycloak. The lab runs it at https://auth.this-is-fine.io with Flux and an HTTPRoute on Envoy Gateway. Below is how Zot uses native OpenID against that issuer.

If you already run a homelab IdP, the interesting part is how little application code must change when the app speaks OIDC natively. Zot is a clear example: configure issuer URL, client ID, and redirect URIs, mount a secret, and the registry UI handles login without an OAuth sidecar in front of it.

Envoy Gateway and the Move from Traefik to Gateway API

 infrastructure 

Three shared gateways replace Traefik-style CRDs — with Headscale as a worked example (public API, private UI).

The lab used to run Traefik with its own CRDs (IngressRoute, Middleware, and friends). Gateway API standardises routes; Envoy Gateway is the controller here — one Helm install, three shared Gateways, and per-app HTTPRoute resources instead of Traefik-only objects.

Traefik is excellent at the edge, but its CRDs are controller-specific. Moving to Gateway API was less about feature envy and more about portability: the same HTTPRoute can be read by another implementation if you ever switch controllers. Envoy Gateway is the implementation here; the routes stay standard Kubernetes objects.

Cosign and Kyverno for ZeroClaw Container Images

 infrastructure   security 

Sign container images in CI, store signatures in OCI — Kyverno refuses unsigned pods at admission.

For images you build yourself, a practical supply-chain loop is: build in CI, sign the digest, verify at admission. The lab uses Cosign (Sigstore), a private Zot registry at oci.this-is-fine.io, and Kyverno verifyImages so unsigned ZeroClaw pods do not start.

CI holds the private signing key; the cluster policy carries the matching public key.

Signing answers a simple question: did this image come from your build pipeline? Scanning for CVEs is still worth doing, but signature verification stops casual image substitution even when a tag name looks familiar.

IRC in the Lab: InspIRCd and a ZNC Bouncer

 infrastructure 

Classic IRC on Kubernetes — InspIRCd for the network, ZNC so clients can disconnect without losing context.

IRC is still a simple model: one server, many channels, text over a long-lived TCP session. InspIRCd runs the network; ZNC is a bouncer that stays logged in when your client disconnects and replays backlog when you return.

In the lab both are plain Deployments under Flux, with TLS from cert-manager and a Gateway API TCPRoute for TLS on port 6697.

IRC is a good contrast to HTTP-only homelab apps: clients expect a long-lived TCP session and often TLS on a non-443 port. Gateway API TCPRoute covers that without bolting IRC into an HTTP ingress controller as a special case.

Cluster-Wide Tailscale: Headscale, Tailnet DNS, and Cross-Cluster Routes

 infrastructure 

Self-hosted Headscale plus a few Kubernetes pieces — private mesh without the official TS operator.

Tailscale builds a WireGuard mesh with little configuration. Headscale is an open control server for the same clients — you run policy and issue keys yourself. The lab does not use the Tailscale Kubernetes operator; a handful of Deployments and DaemonSets do the job instead.

The goal is one tailnet for laptops and nodes, with Kubernetes APIs and internal HTTP on *.tif.internal without putting those names on the public internet.

Self-hosting the control plane means you own ACL files, preauth keys, and MagicDNS base domains. The trade-off is operational work: upgrades, backups, and policy edits are yours. For a multi-cluster lab that already runs GitOps everywhere else, that trade-off is acceptable.

ZeroClaw in the Lab: a GitOps Agent on Matrix

 infrastructure 

An ops-oriented agent on Kubernetes — Matrix chat in, Flux and kubectl out, MCP for the web.

ZeroClaw (nickname Claw) is a small AI agent for cluster work: check Flux status, explain failing pods, dry-run Renovate, draft Git patches. It shares the same GitOps monorepo as the cluster — it is not a second control plane.

You talk to it on Matrix at matrix.this-is-fine.social. Web fetches go through MCP to a Scrapling sidecar instead of built-in browser tools, so there is one audited path for HTTP.

The agent is deliberately ops-focused. It is not a general chatbot for the public internet; it reads cluster state, follows skills checked into Git, and proposes changes that still pass human review. That keeps expectations aligned with what automation can safely do inside a production-shaped lab.

Lab GitOps: Talos, Flux, and a Monorepo

 infrastructure 

Why the lab pairs immutable Talos nodes with Flux CD — and which projects make that workable on ARM.

The lab is a Kubernetes testbed: try cluster layouts here before they go to production. After a short manual bootstrap, Flux keeps the cluster in sync with Git — the usual GitOps loop of declared state in version control and controllers that apply diffs.

Nodes run Talos Linux on Turing Pi RK1 boards. Images come from the Talos Image Factory (metal-arm64, sbc-rockchip / turingrk1). Talos keeps the node OS small and API-driven: you do not SSH in to patch packages. That pushes complexity into Kubernetes manifests, which fits a GitOps workflow.

Everything after the first bootstrap lives in one monorepo: cluster overlays, shared operators, Helm charts, and application kustomizations. Talos machine config (talconfig) is versioned there too, but applied with talosctl, not Flux. Drawing that line clearly avoids pretending the entire world is reconciled from Git when the hypervisor and disk layout are still operator steps.