Skip to content

yabo-san/home-cluster

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

home-cluster

GitOps-driven Kubernetes homelab running on a single-node k3s cluster. Managed by Flux CD with SOPS-encrypted secrets, Kustomize overlays, Longhorn persistent storage, and Cloudflare Tunnel ingress.


Cluster Overview

Component Details
Distribution k3s
GitOps Flux CD v2.8.5
Storage Longhorn
Observability kube-prometheus-stack (Prometheus + Grafana)
Secret Management SOPS + age
Ingress Cloudflare Tunnel
Dependency Updates Renovate (in-cluster CronJob, hourly)

Repository Structure

home-cluster/
├── clusters/
│   └── staging/              # Flux entrypoint — bootstraps all Kustomizations
│       ├── apps.yaml
│       ├── infrastructure.yaml
│       ├── monitoring.yaml
│       ├── storage.yaml
│       └── flux-system/
├── apps/
│   ├── base/                 # Base Kubernetes manifests per app
│   │   ├── audiobookshelf/
│   │   └── linkding/
│   └── staging/              # Staging overlays + secrets + Cloudflare tunnel configs
│       ├── audiobookshelf/
│       └── linkding/
├── infrastructure/
│   ├── controllers/
│   │   └── base/renovate/    # In-cluster Renovate CronJob
│   └── storage/
│       ├── base/             # Shared PVs (NFS media mount)
│       └── longhorn/         # Longhorn HelmRelease + StorageClass + recurring snapshots
└── monitoring/
    ├── controllers/          # kube-prometheus-stack HelmRelease
    └── configs/              # Grafana TLS secret, alerting configs

Apps

Self-hosted bookmark manager. Accessible externally via Cloudflare Tunnel.

  • Image: sissbruecker/linkding:1.45.0
  • Storage: Longhorn-backed PVC
  • Secrets: SOPS-encrypted env secret via Flux

Self-hosted audiobook and podcast server.

  • Image: ghcr.io/advplyr/audiobookshelf:2.33.1
  • Storage: Config and metadata on Longhorn PVCs; audiobook library on NFS host mount (/mnt/media/audiobooks)
  • Ingress: Cloudflare Tunnel
  • Timezone: America/Los_Angeles

Storage

Longhorn is the primary StorageClass (longhorn default, longhorn-retain for stateful workloads requiring reclaim on deletion).

The longhorn-retain class is configured with:

  • 3 volume replicas
  • best-effort data locality
  • ext4 filesystem
  • Daily automated snapshots via Longhorn recurring jobs

A static PV (media-pv) maps the host's NFS media share into the cluster for media library access.


Secret Management

Secrets are encrypted at rest using SOPS with an age key.

The .sops.yaml config encrypts only data and stringData fields in YAML files, keeping the rest of the manifest readable. Flux decrypts secrets at reconciliation time using a sops-age Kubernetes Secret in the flux-system namespace.

Never commit unencrypted secrets. Encrypt before pushing:

sops --encrypt --in-place path/to/secret.yaml

Observability

kube-prometheus-stack (v66.2.2) provides:

  • Prometheus for metrics collection
  • Grafana for dashboards (TLS-terminated)
  • Alertmanager for alerting

Longhorn exposes a ServiceMonitor so storage metrics are scraped automatically.


Dependency Management

Renovate runs in-cluster as a CronJob on an hourly schedule. It watches all .yaml files for image tags and Helm chart versions and opens PRs to keep dependencies current.

Config: renovate.json


Flux Reconciliation

The cluster entrypoint is clusters/staging/. Flux watches this path and reconciles all child Kustomizations from there. Reconciliation intervals:

Kustomization Interval
apps 1m
infrastructure-controllers 1m
infrastructure-storage 1m
monitoring 1m
longhorn 10m

To manually trigger reconciliation:

flux reconcile kustomization flux-system --with-source

To check status across all Kustomizations:

flux get kustomizations
flux get helmreleases -A

Prerequisites

  • k3s installed on target node
  • Flux CLI (flux)
  • SOPS + age key configured locally
  • kubectl with kubeconfig pointed at the cluster
  • Cloudflare account with Tunnel credentials

Bootstrap

flux bootstrap github \
  --owner=yabo-san \
  --repository=home-cluster \
  --branch=main \
  --path=clusters/staging \
  --personal

After bootstrap, create the SOPS age secret:

kubectl create secret generic sops-age \
  --namespace=flux-system \
  --from-file=age.agekey=/path/to/age.key

Planned / In Progress

Sources

About

Homelab cluster

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors