Projects
This page describes how to interact with the homelab depending on your role.
Admin
The admin owns the cluster lifecycle: provisioning hosts, bootstrapping ArgoCD, and curating the apps catalog.
First install
- Prepare the inventory in ansible/inventory/ (hosts, SSH keys, gateway settings).
- Deploy infrastructure and fetch kubeconfig:sh
./run.sh -p ./ansible/install.yml -u -k - Bootstrap the GitOps stack:sh
kubectl config use-context homelab ARGOCD_ADMIN_PASSWORD=<choose-a-password> ./run.sh -b homelab - Once
keycloakis healthy, enable OIDC for the core ArgoCD by uncommenting theoidc.configblock in argo-cd/instances/homelab/values/core/homelab-core.yaml.
Enable / disable services
- Edit argo-cd/instances/homelab/core.yaml (platform tier) or tenant.yaml (apps tier) and flip
enabledon the relevant entry. - Commit & push. The corresponding child AppSet (
core-homelabortenant-homelab) reconciles automatically (no helm/kubectl needed).
Tune service values
- Edit argo-cd/instances/homelab/values/core/<app>.yaml or tenant/<app>.yaml.
- Commit & push. The corresponding
Applicationsyncs the new values.
Adding a new app
- Create a Helm chart under
argo-cd/apps/<app>/(or a wrapper around an upstream chart). - Decide the tier:
- core for infra / identity / observability / security / cluster-wide concerns.
- tenant for user-facing apps.
- tier-flexible for things that may live in either tier depending on topology (e.g. ingress controller, cert-manager, longhorn, keycloak, prometheus-stack, teleport, vault, kubernetes-dashboard). For these, list the entry in BOTH
_example/core.yamlAND_example/tenant.yaml(with appropriatesyncWaves per tier) but only enable it in one tier per concrete instance — enabling it in both would create duplicate Application names.
- Create a values file at
argo-cd/instances/<inst>/values/<tier>/<app>.yaml. - Add an entry in
argo-cd/instances/<inst>/<tier>.yamlwith the appropriatesyncWave. - Commit & push.
Adding a new instance (another cluster / tenant / topology)
- Create the folder
argo-cd/instances/<name>/(copy from _example/ as a template; drop the leading underscore — folders prefixed with_are excluded by the root manager AppSet and treated as templates). - Edit
instance.yamlto set the destination cluster, env, repos, project bindings. - Populate
core.yamland/ortenant.yamlwith the apps the instance should run. - Create
argo-cd/instances/<name>/values/{core,tenant}/mirroring those catalogs (one values file per enabled app, pluscore/homelab-core.yamlif the instance ships its own core ArgoCD). - The root
managerpicks up the new folder automatically. For a brand-new admin cluster, run./run.sh -b <name>once against it; for a tenant-only instance attached to an existing core, just commit & push.
See Installation > Topologies for the all-in-one / SaaS / dedicated-core variants.
Backups & disaster recovery
- Vault is the source of truth for all credentials — back up the
vaultPVC. - PostgreSQL clusters are managed by CloudNative-PG, which can be configured to push base backups + WAL to S3-compatible storage (see
secrets.s3blocks in the secret values). - ArgoCD is fully reconcilable from git — only
argocd-secret(admin password / TLS) needs to survive a reinstall.
Platform user
A platform user consumes the services running on the cluster (Gitea, Mattermost, Grafana, ...). They do not have access to the cluster control plane.
Logging in
- Open <https://sso.<your-domain>>; sign up or use a pre-provisioned account.
- From there, every service listed below uses Keycloak SSO — just click "Login with Keycloak" on the service of choice.
Service catalogue
See Services > Access for the full list of user-facing endpoints (ArgoCD, Coder, Gitea, Grafana, Harbor, Mattermost, RustFS, Outline, SonarQube, Vaultwarden, ...).
Personal ArgoCD sandbox
The user-facing ArgoCD instance lives at <https://gitops.<your-domain>> (in namespace argo-cd). It runs without the manager AppSet — use it to deploy ad-hoc Applications via the UI without affecting the platform.
The "core" ArgoCD that drives the platform itself is internal and not user-facing.
Authoring CI workflows
- Gitea Actions runners are deployed cluster-wide via actions-runner-controller.
- Argo Workflows is available for batch / DAG-style pipelines.
Contributor
Contributors propose changes to the homelab itself (charts, values, scripts, docs).
Workflow
Repository layout
| Path | Purpose |
|---|---|
| ansible/ | Infrastructure (gateway + K3s) provisioning roles & playbooks. |
| utils/helm/ | Bootstrap chart — ships core ArgoCD, the root manager AppSet, and admin-core / admin-tenant AppProjects. |
| argo-cd/apps/ | Helm chart catalog (gitea, keycloak, ..., plus the instance-manager chart used by the root manager). |
| argo-cd/instances/ | Per-instance folders. One per cluster / tenant, each with instance.yaml + core.yaml / tenant.yaml + values/{core,tenant}/<app>.yaml. |
| run.sh | Wrapper around Ansible + Helm with sane defaults. |
Local validation
Before opening a PR:
# Render the bootstrap chart against the homelab instance values
helm template homelab-core ./utils/helm \
-f argo-cd/instances/homelab/values/core/homelab-core.yaml
# Render the per-instance chart for a given instance
helm template instance-homelab ./argo-cd/apps/instance-manager \
-f argo-cd/instances/homelab/instance.yaml \
--set instance.name=homelab
# Lint a specific app chart
helm lint ./argo-cd/apps/<app>
# Validate instance JSON
# Validate instance catalogs (YAML)
yq e '.' argo-cd/instances/homelab/core.yaml >/dev/null
yq e '.' argo-cd/instances/homelab/tenant.yaml >/dev/nullConventions
- One commit per logical change (Conventional Commits format).
- Helm chart bumps go in the chart's
Chart.yaml(subchart deps + parent version). - Per-app values changes go in
argo-cd/instances/<instance>/values/<tier>/<app>.yaml— never in the chart's ownvalues.yaml(which holds defaults only). - Secrets are never committed in plaintext; use Sops (
./run.sh -e). - Mermaid is the only diagram format used in docs.