Skip to content

Introduction

Warning

These docs contain information that relates to my setup. They may or may not work for you.


Cosmo # Lovenet Home Operations Repository _Production-grade Kubernetes for a household._ **GitOps** with Flux ยท **Automated dependency updates** with Renovate ยท **Self-hosted by design**
[![Renovate](https://img.shields.io/badge/Renovate-enabled-1A1F6C?style=for-the-badge&logo=renovatebot&logoColor=white)](https://github.com/rwlove/home-ops/issues/10329) [![Flux](https://img.shields.io/badge/Flux-managed-5468FF?style=for-the-badge&logo=flux&logoColor=white)](https://fluxcd.io) [![Documentation](https://img.shields.io/badge/docs-Material_for_MkDocs-526CFE?style=for-the-badge&logo=materialformkdocs&logoColor=white)](https://rwlove.github.io/home-ops/) [![Check Links](https://img.shields.io/github/actions/workflow/status/rwlove/home-ops/lychee.yaml?label=links&style=for-the-badge)](https://github.com/rwlove/home-ops/actions/workflows/lychee.yaml)
![apps](https://img.shields.io/badge/apps-156-blue?style=for-the-badge) ![helmreleases](https://img.shields.io/badge/HelmReleases-168-326CE5?style=for-the-badge&logo=helm&logoColor=white) ![nodes](https://img.shields.io/badge/k8s_nodes-11-326CE5?style=for-the-badge&logo=kubernetes&logoColor=white) ![cnpg](https://img.shields.io/badge/Postgres_clusters-22-336791?style=for-the-badge&logo=postgresql&logoColor=white) ![secrets](https://img.shields.io/badge/secrets-88-0572EC?style=for-the-badge&logo=1password&logoColor=white) ![age](https://img.shields.io/badge/cluster_age-5%2B_years-success?style=for-the-badge)

๐Ÿ“– Overview

This is the live configuration for a multi-node Kubernetes cluster that runs a household โ€” home automation, security cameras, media, document management, AI workloads, and the operational tooling required to keep it all up. Every change lands in Git first; Flux reconciles the cluster from there, and Renovate keeps dependencies current via PRs.

The repo is GitOps-strict: applications are declared as HelmRelease resources, secrets are pulled from 1Password through External Secrets Operator, and clusters are mostly identical except for app selection and sizing. Operational quirks, durability tiers, and security defaults live alongside the manifests in .agents/instructions/ so the conventions are enforceable, not folklore.


๐Ÿ—บ๏ธ Architecture

flowchart LR
    Dev[๐Ÿ‘ค Operator] -->|git push| Repo[(๐Ÿ“ฆ GitHub<br/>home-ops)]
    Renovate[๐Ÿค– Renovate] -.->|automated PRs| Repo
    Repo -->|reconciles| Flux[โš™๏ธ Flux]
    Flux -->|deploys| Cluster[โ˜ธ๏ธ Kubernetes<br/>11 nodes ยท 188 apps]

    Cluster --> Ceph[(๐Ÿชจ Ceph<br/>block ยท default durable)]
    Cluster --> LH[(๐Ÿ‚ Longhorn<br/>+ recurring backups)]
    Cluster --> Garage[(๐Ÿงบ Garage<br/>S3-compatible)]
    Cluster --> NFS[(๐Ÿ—„๏ธ NFS<br/>beast / brain ยท bulk media)]

    LH -->|weekly + monthly| NFS
    Garage -->|rclone CronJobs| AWS[โ˜๏ธ AWS S3<br/>Glacier Deep Archive<br/>offsite DR]

    classDef store fill:#1e293b,stroke:#475569,color:#e2e8f0
    class Ceph,LH,Garage,NFS,AWS store

Storage tiers are picked deliberately per workload โ€” see storage-class.instructions.md for the decision tree.


๐Ÿงฐ Stack at a glance

Layer Tool Role
OS CentOS Stream 9 / 10 (+ Ubuntu 24.04 on Spark) Node operating system
Runtime cri-o + crun (containerd on Spark) CRI + OCI runtime; Spark is the lone containerd node
Kubernetes v1.35.4 Control-plane and node version
GPU NVIDIA GPU Operator + Container Toolkit P40 on worker8 (Pascal, 24 GB); GB10 on Spark (Grace-Blackwell, 128 GB unified)
GitOps Flux2 Declarative cluster reconciliation
Automation Renovate + GitHub Actions Dependency PRs, link checks, self-hosted runners
CNI Cilium (eBPF) Networking, BGP peering, LoadBalancer pool
Ingress Envoy Gateway L7 gateway / HTTPRoute
Service mesh Istio mTLS + traffic mgmt for mcp-system
Admission Kyverno Namespace-delete blast-radius + audit-mode policies
DNS external-dns Cloudflare + bind9 split-horizon
TLS cert-manager Let's Encrypt + internal CA
Tunnel cloudflared Public ingress without exposing home WAN
AuthN/Z Authelia + Envoy extAuth SSO; per-route SecurityPolicy ext-authz gates apps
Secrets External Secrets Operator + 1Password 116 ExternalSecrets, zero plain-text in Git
VPN wg-easy Operator OOB WireGuard access
Storage Rook-Ceph, Longhorn, Garage, direct NFS Tiered by durability requirement
Databases CloudNative-PG, Dragonfly, Qdrant 24 Postgres clusters, KV, vector
Observability kube-prometheus-stack, Loki, Tempo, Grafana Metrics, logs, traces, dashboards
Telemetry OpenTelemetry Collector + Vector Trace pipeline (โ†’ Tempo) + log shipping (โ†’ Loki)
Images ZOT Pull-through registry / local cache

๐Ÿ–ฅ๏ธ Hardware

Role Hostname Device CPU RAM OS Storage / Accelerators Notes
๐Ÿง  master1 bare-metal 4 32 GB CentOS 10 NVMe (Longhorn) Intel iGPU ยท RTL-SDR ยท control plane
๐Ÿง  master2 VM on beast 3 10.5 GB CentOS 9 virtualized control plane
๐Ÿง  master3 VM on beast 3 10.5 GB CentOS 9 virtualized control plane
๐Ÿ’ช worker2 ThinkCentre M910x 8 32 GB CentOS 9 NVMe (Longhorn + Ceph OSD) ZWA-2 Z-Wave dongle
๐Ÿ’ช worker3 ThinkCentre M910x 8 64 GB CentOS 9 NVMe (Longhorn + Ceph OSD) Sonoff Zigbee dongle
๐Ÿ’ช worker4 ThinkCentre M910x 8 32 GB CentOS 9 NVMe (Longhorn + Ceph OSD) Coral USB TPU
๐Ÿ’ช worker5 VM on beast 10 21.5 GB CentOS 9 NVMe (Longhorn + Ceph OSD)
๐Ÿ’ช worker6 VM on beast 10 26.5 GB CentOS 9 NVMe (Longhorn + Ceph OSD)
๐Ÿ’ช worker7 VM on beast 10 26.5 GB CentOS 9 NVMe (Longhorn + Ceph OSD)
๐ŸŽฎ worker8 VM on beast 10 51.5 GB CentOS 9 NVMe (Longhorn + Ceph OSD) NVIDIA P40 (24 GB VRAM)
๐Ÿš€ spark NVIDIA DGX Spark 20 128 GB Ubuntu 24.04 NVMe + 8 GPU slots NVIDIA GB10 (Grace-Blackwell, 128 GB unified); arm64 ยท containerd outlier

Off-cluster infrastructure

Host Role
beast Dell R730xd ยท iDRAC 8 ยท RAID6 bulk storage ยท primary NFS ยท Longhorn backup target ยท Garage substrate ยท VM host
brain Router/gateway ยท RAID6 mass_storage ยท NFS for downloads & TV ยท OOB SSH on :3231

๐ŸŒ Network

Physical topology (click to expand)
physical network diagram
Network CIDR VLAN
Default 192.168.0.0/16 0
IoT 10.10.20.0/24 20
Guest 10.10.30.0/24 30
Security (cameras) 10.10.40.0/24 40
Kubernetes pod subnet (Cilium) 10.42.0.0/16 โ€”
Kubernetes services subnet (Cilium) 10.43.0.0/16 โ€”
Kubernetes LB pool (CiliumLoadBalancerIPPool) 10.45.0.0/24 โ€”

Worker nodes attach to iot and sec VLANs via Multus for direct camera and IoT-device reachability. Cilium peers BGP with the upstream router to advertise the LB pool; external ingress flows through Envoy Gateway behind cloudflared.


๐Ÿ“ฆ What's running

๐Ÿ  Home Automation โ€” Home Assistant ecosystem, 400+ devices | App | Purpose | |-----|---------| | **Home Assistant** | Primary orchestrator; 400+ Z-Wave / Zigbee / Matter / ESPHome devices | | **ESPHome** | Build & deploy firmware for DIY sensors | | **EMQX** | MQTT broker | | **Node-RED** | Visual automation flows | | **Zigbee2MQTT** | Zigbee bridge (Sonoff stick on worker3) | | **Z-Wave JS UI** | Z-Wave bridge (ZWA-2 stick on worker1) | | **Matter Server** | Matter protocol bridge | | **Frigate** | NVR + ML camera analysis (7+ cameras, Frigate+ trained model) | | **NetBox** | IPAM / DCIM | | **wyoming-services** | Piper TTS + Whisper STT for voice | | **smtp-relay** | Maddy โ†’ Mailgun outbound mail |
๐ŸŽฌ Media & Entertainment โ€” Jellyfin, Immich, Music Assistant, RomM | App | Purpose | |-----|---------| | **Jellyfin** | Primary media server (read-only metadata) | | **Immich** + **immich-pet-tagger** + **immichkiosk** + **immich-power-tools** | Photo library with ML face/pet recognition, offsite-backed | | **Music Assistant** + **Gonic** | Multi-room music control + Subsonic API | | **RomM** | Retro game library (~10k ROMs) | | **Beets** | Music library tagging | | **av1corrector / videodupfinder / medialyze** | Custom video tooling | | **Theme Park** | Consistent UI theming across apps | | **Batocera Webdashboard Pro** | Retro-gaming console dashboard | | **kodi-playback-watcher** | Bridge for Kodi playback state |
๐Ÿค– AI & ML โ€” Local inference, agents, image generation (namespace ai/) | App | Purpose | |-----|---------| | **Ollama** (P40) | Local LLM serving on the Pascal P40 (โ‰ค8b-class models, embeddings) | | **Ollama Spark** | LLM serving on Spark/GB10 (qwen3-next:80b-a3b-instruct-q4_K_M for Open WebUI, bge-m3 embeddings) | | **ComfyUI** | Image generation workflows | | **Khoj** | Personal AI assistant over notes + docs (Authelia extAuth-gated) | | **Paperless-AI** | Auto-tagging for paperless-ngx | | **tei-spark** | Text-embedding-inference reranker (unsuspended 2026-05-21) |
๐Ÿ“Š Observability โ€” Prom/Loki/Grafana | App | Purpose | |-----|---------| | **kube-prometheus-stack** | Prometheus + AlertManager + node-exporter | | **Loki** | Log aggregation | | **Tempo** | Distributed tracing backend (SingleBinary mode) | | **OpenTelemetry Collector** | Trace ingestion pipeline (apps โ†’ OTel โ†’ Tempo) | | **Vector** | Log shipping (sources โ†’ Loki) | | **Grafana** | Dashboards + alerting UI | | **kube-state-metrics / kube-ops-view** | Cluster state & visualization | | **Goldilocks** | VPA-driven resource right-sizing recommendations | | **Kromgo** | Prometheus โ†’ Glance dashboard bridge | | **Netdata** | Per-node real-time metrics | | **network-ups-tools (NUT)** | UPS monitoring & graceful shutdown | | **exporters** | Custom Prometheus exporters |
๐Ÿ—„๏ธ Data & Storage โ€” Databases, object storage, vector search | App | Purpose | |-----|---------| | **CloudNative-PG** | 24 Postgres clusters with WAL archiving to Garage | | **Dragonfly** | Redis-compatible in-memory store | | **Qdrant** | Vector DB for embeddings / RAG | | **pgAdmin** | Postgres admin UI | | **Rook-Ceph** | Distributed block storage (default durable tier) | | **Longhorn** | Block storage with NFS-backed recurring backups | | **Garage** | S3-compatible object storage (DB backups, app S3 workloads) |
๐ŸŒ Network, Auth & Platform โ€” Ingress, SSO, GitOps machinery | App | Purpose | |-----|---------| | **Cilium** | CNI, BGP, LoadBalancer pool | | **Envoy Gateway** | Ingress / HTTPRoute (30 routes) | | **cert-manager** | TLS certificate lifecycle | | **external-dns** | Cloudflare + bind9 record sync | | **cloudflared** | Public tunnel without exposed WAN | | **Authelia** | OIDC identity provider | | **LLDAP** | Lightweight LDAP directory backing Authelia | | **extAuth SecurityPolicies** | per-route Authelia ext-authz gating app SSO | | **wg-easy** | Primary OOB WireGuard access | | **External Secrets Operator** | 1Password-backed secret materialization | | **Flux2** | GitOps reconciler | | **Renovate** | Image & Helm chart update PRs | | **Kuadrant** | MCP server gateway (Authelia-gated JWT) | | **Kyverno** | Admission controller โ€” namespace-delete blast-radius + audit-mode policies | | **actions-runner-controller** | Self-hosted GitHub Actions runners | | **ZOT** | Pull-through registry cache |
๐Ÿ—‚๏ธ Documents & Collaboration โ€” Personal knowledge stack + self-hosted tools | App | Purpose | |-----|---------| | **Paperless-ngx** | Document scanning, OCR, tagging (CNPG-backed, offsite-backed) | | **Obsidian** + **obsidian-couchdb** | Notes sync (CouchDB w/ Cloudflare rate-limiting) | | **Zulip** | Self-hosted team chat | | **Windmill** | Workflow automation; 8 checked-in TypeScript flows under `kubernetes/apps/home/windmill/workflows/` cover the unified paperlessโ†’Qdrant+LightRAG fan-out ingest, paperless + LightRAG RAG tombstones, HA smart-home intent drift, Windmill self-failure-watch, and the workaround upstream-watcher. (The two original split ingests โ€” `paperless-rag-ingest` (Qdrant) + `lightrag-rag-ingest` (graph) โ€” were merged into `paperless-rag-fanout` on 2026-07-20; their `.ts` remain and their schedules are paused for rollback. Down from 23 โ€” the 16 langgraph-agents-fleet-specific flows, including the inbox/approval/digest/DLQ/cost-cap/awaiting-user/reviewer-weekly scripts and the Zulip triager webhook, were removed 2026-07-06 along with the fleet.) | | **ntfy** | Self-hosted push notifications (operator approvals via Android tap actions) | | **BentoPDF** | Self-hosted PDF toolkit | | **Kitchenowl** | Shopping lists + recipe / meal management | | **Open WebUI** | Self-hosted LLM frontend; routes chat to Ollama-Spark (default) / Ollama-P40, and pulls in the MCP gateway as its only tool server (the langgraph-agent-as-model registration and the HolmesGPT tool server were both removed 2026-07-06). RAG via bge-m3 + bge-reranker-v2-m3 over Qdrant | | **SearXNG** | Privacy-respecting metasearch engine | | **Glance** | Personal dashboard / start page | | **Atuin** | Encrypted shell-history sync across machines | | **IT-Tools** | Self-hosted developer toolbox | | **MediKeep** | Personal medical records | | **Nametag** | Name tag / badge generator | | **Pump** + **Pump-cv** | Custom personal apps (`rwlove`-built) |
๐Ÿ”Œ MCP Servers โ€” 19 Model Context Protocol servers behind an Authelia-gated gateway | Server | Exposes | |--------|---------| | **mcp-gateway** | Aggregating gateway; Envoy SecurityPolicy validates Authelia-issued JWTs (daily-rotated key) | | **ha-mcp** | Home Assistant entities + service calls | | **esphome-mcp** | ESPHome dashboard: device YAML edit, validate, logs, compile + OTA flash | | **immich-mcp** | Immich library search + asset metadata | | **kubectl-mcp** | Cluster introspection + safe `kubectl` ops | | **grafana-mcp** | Grafana dashboards + Loki/Prom queries | | **prometheus-mcp** | Direct PromQL access | | **paperless-mcp** | Paperless-ngx document search | | **netbox-mcp** | NetBox IPAM / DCIM | | **github-mcp** | GitHub repo + PR ops | | **omada-mcp** | TP-Link Omada controller | | **searxng-mcp** | Privacy search through SearXNG | | **arr-mcp** | Library-search interface to media-pull apps | | **time-mcp** | Time / timezone utilities (`rwlove/time-mcp` native-SHTTP build) | | **chrome-mcp** | Playwright-driven Chromium browser automation for agents | | **memory-mcp** | Cross-agent knowledge graph backed by Postgres + pgvector (bge-m3 1024-dim) | | **cilium-mcp** | Read-only Cilium / Hubble introspection (kubectl-mcp-style, Cilium-scoped) | | **windmill-mcp** | Aggregated Windmill workspace tools (script run, flow trigger) |

๐Ÿง  AI architecture (overview)

Local-first by default โ€” chat and retrieval today; the automated agent fleet and its cloud-escalation gate were both removed 2026-07-06 (see Current state below). Claude Code (this CLI) is available for interactive, operator-driven use, but there is no automated pipeline that reaches it or the Claude API on its own.

๐Ÿ“– Full chapter: see docs/src/ai_architecture.md for per-app integration paths, RAG pipelines, the historical agent-fleet roster, and the file:line references behind every claim here.

flowchart TB
    subgraph Surfaces[Surfaces]
        OWUI[Open WebUI<br/>chat + RAG]
        Khoj[Khoj<br/>personal AI]
    end

    subgraph Bridges[Windmill bridges<br/>8 TS workflows]
        WPaperless[paperless-rag-ingest/tombstone.ts]
        WLightrag[lightrag-rag-ingest/tombstone.ts]
        WOther[smart-home-intent-drift.ts ยท<br/>windmill-failure-watcher.ts ยท<br/>workaround-watcher.ts]
    end

    subgraph Inference[Inference]
        OllamaP40[(ollama / P40<br/>qwen2.5:7b ยท embeddings)]
        OllamaSpark[(ollama-spark / GB10<br/>qwen3-next:80b-a3b-instruct-q4_K_M ยท bge-m3)]
    end

    subgraph Tools[Tools + retrieval]
        Gw[MCP Gateway<br/>19 servers]
        Q[(Qdrant<br/>vector DB)]
        Mem[(memory-mcp<br/>pgvector KG)]
    end

    subgraph Outputs[Outputs + observability]
        AM[AlertManager]
        Push[Pushover<br/>direct page]
    end

    OWUI -->|chat| OllamaSpark
    OWUI --> Gw --> Mem
    OWUI --> Q
    Khoj --> OllamaP40
    WPaperless --> Q
    WLightrag --> Q
    AM --> Push

There's no agent fleet, no gated Claude API lane, and no OTLP trace producer left in this diagram โ€” all three were langgraph-agents plumbing, removed 2026-07-06 along with the fleet.

Surfaces and bridges

  • Open WebUI (collab/) โ€” primary chat UI. Defaults to qwen3-next:80b-a3b-instruct-q4_K_M on Ollama-Spark. RAG runs over Qdrant with bge-m3 embeds + BGE reranker-v2-m3 in-process. Tool server wired in: the MCP gateway (the langgraph-agent-as-model registration and the HolmesGPT tool server are both gone).
  • Khoj (ai/) โ€” parallel personal-AI surface for notes + docs. Self-contained: own embedding pipeline (default gte-small, optionally ollama nomic-embed-text), chat via Ollama-P40. Does not consume the MCP gateway.
  • HolmesGPT โ€” removed 2026-07-06 (no value delivered). The windmill-investigate route/receiver and the alertmanager-holmesgpt-notify.ts bridge were removed in Stage 1 (critical alerts now go straight to Pushover); the HolmesGPT deployment itself, its RBAC, its Open WebUI tool-server registration, and its Ollama/Authelia wiring were removed in Stage 2. HolmesGPT no longer exists anywhere in the cluster.
  • langgraph-agents โ€” removed 2026-07-06. The FastAPI multi-agent runtime, its Postgres checkpoints (postgres-langgraph-checkpoints, deleted), vault PVCs (langgraph-vault/langgraph-vault-rw, deleted), and both public routes (hai.${SECRET_DOMAIN} and hai-web.${SECRET_DOMAIN}) are gone. sync-receiver โ€” an sshd sidecar that existed solely to expose the langgraph-vault PVCs over rsync โ€” was deleted alongside it. See Agent fleet โ€” status today for the historical roster.
  • Windmill (home/) โ€” 8 checked-in TypeScript flows remain under kubernetes/apps/home/windmill/workflows/ (down from 23): the unified paperless-rag-fanout ingest (Qdrant + LightRAG from one pull), Paperless + LightRAG RAG tombstones, HA smart-home intent drift, Windmill self-failure-watch, and the workaround upstream-watcher. The two original split ingests (paperless-rag-ingest, lightrag-rag-ingest) were merged into the fan-out 2026-07-20 โ€” retained on disk, schedules paused for rollback. The 16 langgraph-fleet-specific flows (inbox, approval post/receive, daily digest, cost-cap watcher, awaiting-user sweep, DLQ watcher, weekly operator-drift crons, the approval-flow smoke test, and the Zulip triager webhook) were deleted 2026-07-06.
  • Langfuse โ€” removed 2026-07-06. Its only consumer (langgraph-agents) was already gone; the keep-dormant-vs-remove question is now resolved as remove.
  • memory-mcp (mcp-system/) โ€” cross-agent knowledge graph on postgres-langgraph-memory with pgvector(1024), bge-m3 embeds via Ollama-Spark. Fully unaffected by the decommission โ€” it's memory-mcp's own database, used by Claude Code and Open WebUI. It just lost langgraph-agents as a consumer.

Agent fleet โ€” retired 2026-07-06

The langgraph-agents multi-agent fleet (triager, supervisor, historian, reporter, reviewer, the five operator personas โ€” storage/network/observability/ml/smart-home โ€” plus errand-runner, researcher, homelab-engineer, and eight more wired-but-cold agents) was removed in its entirety. There is no automated agent pipeline in the cluster today. The full historical roster with per-agent role and trigger detail lives in docs/src/ai_architecture.md, preserved as a record of what was built and retired โ€” not as a status board for anything currently running.

Local-first routing tiers

Tier Backend When used
1 qwen2.5:7b on Ollama (P40) Fast / simple chat, embeddings, voice STT/TTS support
2 qwen3-next:80b-a3b-instruct-q4_K_M on Ollama-Spark (GB10) Default chat inference (Open WebUI)

Removed 2026-07-06: the third tier โ€” gated Claude API escalation via langgraph-agents (ENABLE_CLAUDE_API, cost caps $5/task ยท $10/agent/day ยท $30/global/day) โ€” is gone along with the fleet. There is no automated cloud-escalation tier today.

Voice-to-action: retired, known gap

Before 2026-07-06, holding the phone's power button and saying "inbox <whatever I'm thinking>" routed through Whisper STT โ†’ an HA rest_command โ†’ Windmill โ†’ langgraph-agents /inbox, which triaged the note to a specialist agent and synced results to the Obsidian vault. That backend is gone.

Known gap, not yet fixed: the HA voice rest_command (defined in the separate home-assistant-config repo) still exists and still POSTs toward the deleted Windmill webhook โ€” it will silently fail. The full original design (mermaid diagram + step-by-step path) is preserved as a historical record in docs/src/workflow_automation.md.

Alert triage

There is no automated investigation step today. AlertManager fires a critical alert and pages Pushover directly. HolmesGPT used to sit in between (querying Prometheus, Loki, and the cluster to build a root-cause hypothesis before posting back via Windmill) but was removed 2026-07-06 โ€” no value delivered.

Current state (2026-07-06)

  • HolmesGPT โ€” removed. No longer deployed anywhere in the cluster.
  • LangGraph fleet โ€” removed in its entirety: the FastAPI runtime, postgres-langgraph-checkpoints, the langgraph-vault/langgraph-vault-rw PVCs, both public routes (hai.${SECRET_DOMAIN}, hai-web.${SECRET_DOMAIN}), and sync-receiver. 16 of 23 Windmill workflows deleted with it. postgres-langgraph-memory and memory-mcp are kept โ€” that database is memory-mcp's own backend, unaffected by this decommission. Known gap: the HA voice "inbox โ€ฆ" intent is now broken (see Voice-to-action above).
  • claude-runner โ€” retired 2026-05-23, superseded by the langgraph fleet (its two CronJobs graduated into agent workflows inside langgraph-agents). With langgraph-agents now also removed, that functionality is gone twice over โ€” there is no automated Claude Code or Claude API pipeline anywhere in the cluster today. Claude Code use is interactive-only (an operator running the CLI, same as the session that made this edit).
  • KubeClaw โ€” retired (memo project_open_issues_cleanup_2026_05_20).

โ˜๏ธ Cloud dependencies

Service Use Cost
1Password Secret backend for External Secrets ~$65 / yr
Cloudflare Domain, DNS, tunnel, WAF rate-limiting Free
GitHub Repo hosting + CI Free
Mailgun Outbound mail relay (via Maddy) Free (Flex)
Pushover Push notifications for AlertManager + apps $10 one-time
Frigate+ Trained ML model for Frigate NVR $50 / yr
AWS S3 Glacier Deep Archive Offsite DR for Immich + Paperless (objects + DB backups) ~$1โ€“5 / mo (varies)
~$10โ€“15 / mo

๐Ÿ›ก๏ธ Operational pillars

๐Ÿ’พ Tiered storage durability

Four tiers, picked by what the data has to survive โ€” node loss, Ceph loss, cluster loss, or full site loss. Databases get ceph-block + Barmanโ†’Garage; irreplaceable state goes to Longhorn with NFS-shipped weekly + monthly backups; S3-shaped workloads use Garage; bulk media rides direct NFS. Full decision tree: .agents/instructions/storage-class.instructions.md.

๐Ÿ” Secrets โ€” zero plain-text in Git

All 116 ExternalSecrets resolve through External Secrets Operator from 1Password. Application credentials are templated into ExternalSecret resources and never live in YAML. Cross-namespace mirrors use the reflector pattern when consumer charts hard-code secret names.

๐Ÿชช Authentication โ€” single sign-on everywhere

Authelia (with LLDAP) is the identity provider; per-route Envoy Gateway SecurityPolicy extAuth (Authelia's ext-authz endpoint) enforces auth at the gateway โ€” 26 apps sit behind SSO today, tiered admin vs household via access_control rules (the oauth2-proxy sidecar fleet was retired 2026-07-01, #12767). Native-OIDC apps (immich, paperless, open-webui, โ€ฆ) authenticate against Authelia directly. The mcp-gateway validates Authelia-issued JWTs with a daily-rotated signing key for MCP tooling.

๐Ÿ”ญ Observability โ€” metrics, logs, dashboards

kube-prometheus-stack scrapes everything; Loki ingests pod logs (via Vector); Tempo ingests traces (via OpenTelemetry Collector); Grafana stitches the dashboards. AlertManager fans critical alerts straight to Pushover โ€” no automated triage step (the HolmesGPT investigation path was removed 2026-07-06).

๐ŸŽฎ GPU workloads

Two GPUs split the workload:

  • NVIDIA P40 on worker8 (Pascal, 24 GB VRAM) โ€” Ollama for โ‰ค8b-class models + embeddings, ComfyUI, Whisper STT, Immich CLIP face/pet recognition, and the immich-pet-tagger fork pinned to a P40-compatible PyTorch build.
  • NVIDIA GB10 on Spark (Grace-Blackwell, 128 GB unified) โ€” the larger Ollama deployment serving qwen3-next:80b-a3b-instruct-q4_K_M for Open WebUI, plus bge-m3 embeddings for the cross-agent knowledge graph and Paperless RAG.

Driver lifecycle is handled by the NVIDIA GPU Operator. Spark is the lone containerd node in an otherwise CRI-O cluster; a NodeFeatureRule auto-skips the GPU container-toolkit DaemonSet on CRI-O nodes.

๐Ÿ›Ÿ Disaster recovery

Per-app rclone CronJobs ship Immich originals and Paperless documents โ€” plus their Garage-stored Postgres backups โ€” to encrypted AWS S3 with a 1-day Glacier Deep Archive transition. Recovery procedure is documented at Offsite recovery and was last validated 2026-05-05.

๐ŸŒช๏ธ Strict GitOps

Every change reaches the cluster through Git. Flux suspends are a deliberate manual signal โ€” paused Kustomizations are not "broken," they're intentional pauses for in-flight maintenance and are documented in conventions, not reverted on sight.


๐Ÿ“š Documentation

The full operator handbook lives at https://rwlove.github.io/home-ops/.

Frequently referenced pages:

Repo-local conventions (auto-loaded by AI agents from .agents/instructions/):

  • Storage class selection ยท HelmRelease security defaults ยท ConfigMap layout ยท Sorting rules ยท Schema correction ยท Persona

๐Ÿ™ Acknowledgements

Inspired by the k8s-at-home community. @whazor maintains the excellent k8s-at-home search โ€” a great way to discover how others configure the same Helm releases.

This repo has been continuously reconciling itself since March 2021.