{"id":13821003,"url":"https://github.com/gavinmcfall/home-ops","last_synced_at":"2026-01-18T07:45:03.335Z","repository":{"id":215538622,"uuid":"739170096","full_name":"gavinmcfall/home-ops","owner":"gavinmcfall","description":"HomeOps driven by Kubernetes and GitOps using Flux","archived":false,"fork":false,"pushed_at":"2026-01-16T12:07:20.000Z","size":35807,"stargazers_count":32,"open_issues_count":60,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-16T12:38:22.217Z","etag":null,"topics":["ansible","flux","gitops","k3s","k8s-at-home","kubernetes","kubesearch","renovate","self-hosted"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gavinmcfall.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-01-04T23:52:22.000Z","updated_at":"2026-01-16T08:14:46.000Z","dependencies_parsed_at":"2024-02-08T15:30:23.100Z","dependency_job_id":"b0cde5a3-4def-4a65-b1da-ef6516986d76","html_url":"https://github.com/gavinmcfall/home-ops","commit_stats":null,"previous_names":["gavinmcfall/home-ops"],"tags_count":6,"template":false,"template_full_name":"onedr0p/cluster-template","purl":"pkg:github/gavinmcfall/home-ops","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinmcfall%2Fhome-ops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinmcfall%2Fhome-ops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinmcfall%2Fhome-ops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinmcfall%2Fhome-ops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gavinmcfall","download_url":"https://codeload.github.com/gavinmcfall/home-ops/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinmcfall%2Fhome-ops/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28533172,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"online","status_checked_at":"2026-01-18T02:00:07.578Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","flux","gitops","k3s","k8s-at-home","kubernetes","kubesearch","renovate","self-hosted"],"created_at":"2024-08-04T08:01:13.470Z","updated_at":"2026-01-18T07:45:03.314Z","avatar_url":"https://github.com/gavinmcfall.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"https://raw.githubusercontent.com/gavinmcfall/home-ops/main/docs/src/assets/logo.png\" align=\"center\" width=\"144px\" height=\"144px\"/\u003e\n\n### My Home Operations Repository :octocat:\n\n_... managed with Flux, Renovate, and GitHub Actions_ 🤖\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Discord](https://img.shields.io/discord/673534664354430999?style=for-the-badge\u0026label\u0026logo=discord\u0026logoColor=white\u0026color=blue)](https://discord.gg/home-operations)\u0026nbsp;\u0026nbsp;\n[![Talos](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Ftalos_version%3Fformat%3Dendpoint\u0026style=for-the-badge\u0026logo=talos\u0026logoColor=white\u0026color=blue\u0026label=%20)](https://talos.dev)\u0026nbsp;\u0026nbsp;\n[![Kubernetes](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fkubernetes_version%3Fformat%3Dendpoint\u0026style=for-the-badge\u0026logo=kubernetes\u0026logoColor=white\u0026color=blue\u0026label=%20)](https://kubernetes.io)\u0026nbsp;\u0026nbsp;\n[![Flux](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fflux_version%3Fformat%3Dendpoint\u0026style=for-the-badge\u0026logo=flux\u0026logoColor=white\u0026color=blue\u0026label=%20)](https://fluxcd.io)\u0026nbsp;\u0026nbsp;\n[![Renovate](https://img.shields.io/github/actions/workflow/status/gavinmcfall/home-ops/renovate.yaml?branch=main\u0026label=\u0026logo=renovatebot\u0026style=for-the-badge\u0026color=blue)](https://github.com/gavinmcfall/home-ops/actions/workflows/renovate.yaml)\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Home-Internet](https://img.shields.io/uptimerobot/status/m796131834-31972b9c59792f91867b7e32?color=brightgreeen\u0026label=Home%20Internet\u0026style=for-the-badge\u0026logo=ubiquiti\u0026logoColor=white)](https://status.nerdz.cloud)\u0026nbsp;\u0026nbsp;\n[![Status-Page](https://img.shields.io/uptimerobot/status/m796131761-b1397cce0713b97ac72919e8?color=brightgreeen\u0026label=Status%20Page\u0026style=for-the-badge\u0026logo=statuspage\u0026logoColor=white)](https://status.nerdz.cloud)\u0026nbsp;\u0026nbsp;\n[![Alertmanager](https://img.shields.io/uptimerobot/status/m796147470-2b0eda86fc73e344c858b2ac?color=brightgreeen\u0026label=Alertmanager\u0026style=for-the-badge\u0026logo=prometheus\u0026logoColor=white)](https://status.nerdz.cloud)\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Age-Days](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fcluster_age_days%3Fformat%3Dendpoint\u0026style=flat-square\u0026label=Age)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Uptime-Days](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fcluster_uptime_days%3Fformat%3Dendpoint\u0026style=flat-square\u0026label=Uptime)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Node-Count](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fcluster_node_count%3Fformat%3Dendpoint\u0026style=flat-square\u0026label=Nodes)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Pod-Count](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fcluster_pod_count%3Fformat%3Dendpoint\u0026style=flat-square\u0026label=Pods)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![CPU-Usage](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fcluster_cpu_usage%3Fformat%3Dendpoint\u0026style=flat-square\u0026label=CPU)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Memory-Usage](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fcluster_memory_usage%3Fformat%3Dendpoint\u0026style=flat-square\u0026label=Memory)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Power-Usage](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fcluster_power_usage%3Fformat%3Dendpoint\u0026style=flat-square\u0026label=Power)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Alerts](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.nerdz.cloud%2Fcluster_alert_count%3Fformat%3Dendpoint\u0026style=flat-square\u0026label=Alerts)](https://github.com/kashalls/kromgo)\n\n\u003c/div\u003e\n\n---\n\n## 📖 Overview\n\nThis is a mono repository for my home infrastructure and Kubernetes cluster. I try to adhere to Infrastructure as Code (IaC) and GitOps practices using tools like [Kubernetes](https://kubernetes.io/), [Flux](https://github.com/fluxcd/flux2), [Renovate](https://github.com/renovatebot/renovate), and [GitHub Actions](https://github.com/features/actions).\n\n---\n\n## ⛵ Kubernetes\n\nMy Kubernetes cluster is deployed with [Talos](https://www.talos.dev). This is a semi-hyper-converged cluster, workloads and block storage share the same available resources on my nodes while I have a separate server with ZFS for NFS/SMB shares, bulk file storage and backups.\n\nIf you want to try and follow along with how I built my cluster please check out the amazing template here:\n\n[![Flux Cluster Template](https://img.shields.io/badge/Cluster%20Template-1f6feb?style=for-the-badge)](https://github.com/onedr0p/cluster-template)\n[![Flux Cluster Template Stars](https://img.shields.io/github/stars/onedr0p/cluster-template?style=for-the-badge\u0026color=1f6feb)](https://github.com/onedr0p/cluster-template)\n\n### Core Components\n\n- **Networking**: [cilium](https://github.com/cilium/cilium) provides eBPF-based networking replacing kube-proxy, [Envoy Gateway](https://gateway.envoyproxy.io/) implements Gateway API for routing, [cloudflared](https://github.com/cloudflare/cloudflared) secures ingress via Cloudflare tunnels, and [external-dns](https://github.com/kubernetes-sigs/external-dns) + [external-dns-unifi-webhook](https://github.com/kashalls/external-dns-unifi-webhook) keeps DNS records in sync automatically.\n- **Security \u0026 Secrets**: [cert-manager](https://github.com/cert-manager/cert-manager) automates SSL/TLS certificates. [external-secrets](https://github.com/external-secrets/external-secrets) with [1Password Connect](https://github.com/1Password/connect) injects secrets into Kubernetes, and [sops](https://github.com/getsops/sops) manages encrypted secrets in Git.\n- **Storage \u0026 Data Protection**: [rook](https://github.com/rook/rook) provides distributed block storage via Ceph, [volsync](https://github.com/backube/volsync) handles PVC backups and recovery, and [spegel](https://github.com/spegel-org/spegel) runs a stateless cluster-local OCI image mirror.\n- **Automation**: [actions-runner-controller](https://github.com/actions/actions-runner-controller) runs self-hosted GitHub Actions runners in the cluster.\n\n### Installation\n\nMy cluster runs on 3x [Minisforum MS-01](https://store.minisforum.com/products/minisforum-ms-01) mini PCs (Intel i9-12900H) provisioned with [Talos](https://www.talos.dev/). The nodes utilize [Thunderbolt ring networking](https://gist.github.com/gavinmcfall/ea6cb1233d3a300e9f44caf65a32d519) for high-speed Ceph storage traffic.\n\n**Talos Extensions:**\n- `siderolabs/i915` - Intel GPU microcode binaries and drivers\n- `siderolabs/intel-ucode - Intel microcode binaries\n- `siderolabs/mei` - Intel Management Engine drivers kernel modules\n- `siderolabs/thunderbolt` - Thunderbolt/USB4 drivers kernel modules\n- `siderolabs/util-linux-tools` - Linux Utilities\n\n**Talos extraKernelArgs** - Less Security (home-lab its fine) = Greater performance gains\n- `intel_iommu=on` - Enables Intel VT-d hardware virtualization support\n- `iommu=pt` - Passthrough mode, better performance for devices\n- `mitigations=off` - Disables CPU vulnerability patche\n- `selinux=0` - Disables SELinux mandatory access control system\n- `apparmor=0` - Disables AppArmor mandatory access control system\n- `init_on_alloc=0` - Skips zeroing memory when allocating it\n- `init_on_free=0` - Skips zeroing memory when freeing it\n- `security=none` - Disables all Linux Security Modules entirely\n- `talos.auditd.disabled=1` - Disables Talos audit logging daemon service\n\n### GitOps\n\n[Flux](https://github.com/fluxcd/flux2) watches the cluster in my [kubernetes](./kubernetes/) folder and makes changes based on the state of this Git repository.\n\nThe way Flux works for me here is it will recursively search the `kubernetes/apps` folder until it finds the most top level `kustomization.yaml` per directory and then apply all the resources listed in it. That `kustomization.yaml` will generally only have a namespace resource and one or many Flux kustomizations (`ks.yaml`). Under the control of those Flux kustomizations there will be a `HelmRelease` or other resources related to the application which will be applied.\n\n[Renovate](https://github.com/renovatebot/renovate) watches my **entire** repository looking for dependency updates, when they are found a PR is automatically created. When some PRs are merged Flux applies the changes to my cluster.\n\n### Flux Workflow\n\nThis is a high-level look at how Flux deploys applications with dependencies. A `HelmRelease` can depend on other `HelmRelease`s, a `Kustomization` can depend on other `Kustomization`s, or an app can depend on both. Below shows that `atuin` won't deploy until `rook-ceph-cluster` is healthy.\n\n![Flux Workflow](./docs/src/assets/graphics/flux-workflow.png)\n\n\n### Directories\n\nThis Git repository contains the following directories:\n\n```sh\n📁 kubernetes\n├── 📁 apps           # applications\n├── 📁 bootstrap      # bootstrap procedures\n├── 📁 flux           # core flux configuration\n└── 📁 components     # re-useable kustomize components\n📁 bootstrap\n└── 📁 templates      # Makejinja templates (source files)\n```\n\n---\n\n## 💾 Backup Architecture\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick to expand backup strategy\u003c/summary\u003e\n\n![Backup Strategy](./docs/ai-context/images/claude_backup_strategy.png)\n\n### Backup Flows\n\n| Flow | Tool | Destinations | Schedule |\n|------|------|--------------|----------|\n| Application PVCs | VolSync + Kopia | NFS (hourly), B2/R2 (daily) | Hourly/Daily |\n| NFS to Cloud | Kopia Server | B2 (2 AM), R2 (3 AM) | Daily |\n| PostgreSQL | pgBackRest | B2 (3 AM), R2 (4 AM) | Daily |\n| Images | TrueNAS Cloud Sync | B2 | TrueNAS scheduled |\n\nFor details, see the [Backup Strategy Guide](./docs/Guides/Storage/Backup-Strategy/README.md).\n\n\u003c/details\u003e\n\n---\n\n## 🌐 Networking\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick to expand network architecture\u003c/summary\u003e\n\n### Network Topology\n\n![Network Topology](./docs/src/assets/graphics/network-topology.png)\n\n### Key Concepts\n\n- **Split-Horizon DNS**: LAN clients resolve to the internal gateway (10.90.3.202), external clients go through Cloudflare\n- **Gateway API**: Envoy Gateway provides `external` and `internal` gateways for traffic routing\n- **Thunderbolt Ring**: Full-mesh ~26 Gbps connectivity between nodes for Ceph replication traffic\n\nFor details on setting up Thunderbolt networking, see my [guide](https://gist.github.com/gavinmcfall/ea6cb1233d3a300e9f44caf65a32d519).\n\n\u003c/details\u003e\n\n---\n\n## ☁️ Cloud Dependencies\n\n| Service | Use | Cost (NZD) |\n|---------|-----|------|\n| [Cloudflare](https://www.cloudflare.com/) | DNS, Tunnel, CDN, R2(Volsync), Domain renewel | ~$25/yr |\n| [Backblaze](https://www.backblaze.com/) | B2(Volsync) | ~$30/yr |\n| [1Password](https://1password.com/) | Secrets via Connect (Family plan with 5 seats) | ~$135/yr |\n| [UptimeRobot](https://uptimerobot.com/) | Status monitoring | ~$80/yr |\n| [GitHub](https://github.com/) | Code hosting, Actions | Free |\n| [Pushover](https://pushover.net) | Push notifications from Alert Manger and UptimeRobot | $4.99 USD One Time |\n| [Migadu](https://migadu.com/) | SMTP for services | ~$40/yr (Micro plan) |\n\n---\n\n## 🔧 Hardware\n\n### Kubernetes Cluster\n\n| Node | CPU | RAM | OS Disk | Ceph Disk | OS | Purpose |\n|------|-----|-----|---------|-----------|-----|---------|\n| stanton-01 | i9-12900H (14c/20t) | 96GB | 1TB Samsung 990 Pro | 1.92TB Samsung PM9A3 U.2 | Talos | Control + Worker |\n| stanton-02 | i9-12900H (14c/20t) | 96GB | 1TB Samsung 990 Pro | 1.92TB Samsung PM9A3 U.2 | Talos | Control + Worker |\n| stanton-03 | i9-12900H (14c/20t) | 96GB | 1TB Samsung 990 Pro | 1.92TB Samsung PM9A3 U.2 | Talos | Control + Worker |\n\n**Totals:** 42 cores / 60 threads | 288GB RAM | ~5.76TB Ceph\n\n\u003e *Nodes named after the [Stanton system](https://www.robertsspaceindustries.com/enlist?referral=STAR-6WG5-BTYL) in Star Citizen. See you in the 'verse, citizen! o7*\n\u003e\n\u003e *— [NZVengeance](https://robertsspaceindustries.com/en/citizens/NZVengeance)*\n\n### Supporting Infrastructure\n\n| Device | Count | Storage | RAM | OS | Purpose |\n|--------|-------|---------|-----|-----|---------|\n| Dell PowerEdge R730 | 1 | 4x Mirror vdevs (~18TB) + NVMe cache | 128GB | Proxmox/TrueNAS | NAS/Backup |\n| Unifi Dream Machine Pro | 1 | - | - | - | Router/Firewall |\n| Unifi US-24-250W | 1 | - | - | - | PoE Switch |\n| Unifi US-48 | 1 | - | - | - | Primary Switch |\n| Unifi U6 Lite | 3 | - | - | - | WiFi APs |\n| JetKVM + DC Power Module | 3 | - | - | - | Remote KVM |\n| Eaton 5S 850 | 2 | - | - | - | UPS |\n\n---\n\n## ⭐ Stargazers\n\n\u003ca href=\"https://star-history.com/#gavinmcfall/home-ops\u0026Date\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/svg?repos=gavinmcfall/home-ops\u0026type=Date\u0026theme=dark\" /\u003e\n    \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/svg?repos=gavinmcfall/home-ops\u0026type=Date\" /\u003e\n    \u003cimg alt=\"Star History Chart\" src=\"https://api.star-history.com/svg?repos=gavinmcfall/home-ops\u0026type=Date\" /\u003e\n  \u003c/picture\u003e\n\u003c/a\u003e\n\n---\n\n## 🤝 Gratitude and Thanks\n\nThanks to all the people who donate their time in the [Home Operations](https://discord.gg/home-operations) Discord community for all of their support. Special shout out to my friend and colleague [Kevin Durbin](https://github.com/kevindurb).\n\nCheck out my [blog](https://blog.nerdz.cloud/) for more homelab content.\n\nAlso check out my [Guides](./docs/Guides/)\n\n---\n\n## 📜 Changelog\n\nSee my _awful_ [commit history](https://github.com/gavinmcfall/home-ops/commits/main)\n\n---\n\n## 🔏 License\n\nSee [LICENSE](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgavinmcfall%2Fhome-ops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgavinmcfall%2Fhome-ops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgavinmcfall%2Fhome-ops/lists"}