Homelab GitOps uses two Git repositories with different jobs. Argo CD consumes both directly — do not sync or mirror one repo into the other.
| Repository | Role |
|---|---|
homelabs (public) | Reusable Kubernetes baseline: generic Helm values, manifests, Ansible defaults, .template files |
homelabs-private (private) | Cluster desired state: real hostnames/IPs, per-app value overlays, RBAC bindings, Argo CD Application manifests, bootstrap scripts |
Documentation lives in this site (website/docs/). Each Git repo has only one README.md at its root — a short pointer here. Do not add README files under subdirectories.
What goes in homelabs (public)#
Share anything another cluster could reuse without your secrets or site-specific identifiers:
- Generic Helm
values.yamlwith placeholders (dex.example.com,your-github-org) - Namespace,
ExternalSecret, and Kustomize bases *.yaml.templatefiles for manual bootstrap fallbacks- Ansible / Terraform defaults with example values
- Non-secret deployment manifests (e.g.
cloudflaredDeployment shape)
| Path | Purpose |
|---|---|
dex/ | Dex OIDC broker template values + shared manifests |
plex/ | Plex Helm values + namespace/PVC/ExternalSecret base |
pihole/ | Pi-hole manifests |
cloudflare/ | cloudflared Deployment for token-managed tunnel |
vault/ | Vault Helm values template |
kubernetes/k3s-ansible/ | k3s install inventory with generic OIDC placeholders |
Keep Namespace objects in Git so Argo CD prune stays predictable. Keep CreateNamespace=true on Applications as a safety net.
What stays in homelabs-private (private)#
Keep the smallest set of files that must differ per cluster:
clusters/<cluster>/config/cluster.yaml— IPs, domain, admin email, SSH targetsclusters/<cluster>/overlays/<app>/values.yaml— production Helm overridesclusters/<cluster>/manifests/— site-specific RBAC, secrets wiring (not plaintext secrets)clusters/<cluster>/argocd/applications/— Argo CD Application definitions (multi-source)clusters/<cluster>/scripts/— one-off bootstrap or day-2 patch scriptsclusters/<cluster>/kubeconfig-*.yaml.template— workstation templates with real API endpointsclusters/<cluster>/ansible/group_vars/— overrides for public Ansible defaultsargocd/projects/— AppProject allow-lists
Never commit filled secrets, OAuth client secrets, tokens, or kubeconfig files with credentials. Use .gitignore for generated secret files; prefer Vault + External Secrets Operator.
Argo CD multi-source pattern#
Each Application typically references:
- Upstream Helm chart (if any)
- Public
homelabspath (shared manifests or$valuesref) - Private
homelabs-privatepath (overlay values, RBAC, cluster wiring)
Example (Dex): chart from charts.dexidp.io + homelabs/dex/manifests + private overlays/dex/values.yaml + private RBAC. See Dex OIDC.
Local workspace layout#
The development folder mi/ on the NAS groups the repos side by side (not a single git root):
mi/
├── homelabs/ # public repo
├── homelabs-private/ # private repo
├── website/ # Hugo docs site
└── plan.md # local runbooks (not committed)When writing or moving files, default to website docs first, then the smallest code change in the correct repo.
Related#
- Argo CD — install, app-of-apps, repository credentials
- Dex OIDC — concrete public/private split for cluster login
- Blog: public GitOps without leaking secrets