9.8 KiB
Homelab
Configuration for my homelab: Kubernetes manifests, Docker Compose stacks, and the Gitea Actions that build and deploy them. Most applications have both deployment formats. Headscale, Nextcloud AIO, and the media stack run on Docker; Kubernetes provides their ingress through Services and EndpointSlices.
These files contain this lab's domains, IP addresses, storage paths, and private registry names. Running them on another machine takes some editing.
Start here
- Service list — what each directory contains.
- Deployment workflow — selection, validation, and recovery.
- Repository review — confirmed problems and fix branches.
- Shared PostgreSQL, Traefik, and cert-manager — common dependencies.
What gets deployed
The active files are switches for the deploy workflow, not health indicators.
| File | Effect |
|---|---|
<service>/active |
Include that directory's compose.yaml or compose.yml. |
<service>/k8s/active |
Include its Kubernetes manifests or Kustomize overlay. |
| Both | Run the Compose stack and apply the Kubernetes resources. |
| Neither | Keep the configuration in Git without automatic deployment. |
shared-compose.yaml, client.compose.yaml, and renovate-compose.yaml are
manual entry points. The deploy script does not discover them.
Kubernetes selection excludes secret files, examples, Helm values, and patches.
Helm releases listed in deploy-lib.sh are upgraded separately. Traefik,
cert-manager, and CrowdSec have additional bootstrap steps; an active marker
does not install their charts.
The table below describes committed configuration. It does not claim that a service is currently healthy or running.
Services
| Service | Configuration | Selected by markers |
|---|---|---|
| AdGuard Home | Kubernetes + Compose | Kubernetes |
| Authentik | Kubernetes + Compose | Kubernetes |
| cert-manager | Kubernetes / Helm | Manual |
| Cloudflare DDNS | Kubernetes + Compose | Kubernetes |
| Checkmk | Kubernetes + Compose | Manual |
| Cloudflare Tunnel | Kubernetes / Helm | Manual |
| File converters | Kubernetes + Compose | Kubernetes |
| CrowdSec | Kubernetes / Helm | Manual |
| Dockmon | Kubernetes + Compose | Manual |
| Downtify | Kubernetes + Compose | Manual |
| EDU session keeper and Telegram bot | Kubernetes + Compose | Kubernetes |
| Error pages | Kubernetes + Compose | Kubernetes |
| Gitea | Kubernetes + Compose | Kubernetes |
| Glance | Kubernetes + Compose | Manual |
| Headscale | Compose + Kubernetes routing | Compose, Kubernetes |
| Homarr | Kubernetes + Compose | Manual |
| Homepages | Kubernetes + Compose | Kubernetes |
| Immich | Kubernetes + Compose | Kubernetes |
| Kener | Kubernetes + Compose | Manual |
| Loki and Alloy | Kubernetes / Helm | Kubernetes |
| MeTube | Kubernetes + Compose | Kubernetes |
| n8n | Kubernetes + Compose | Manual |
| NetBird | Kubernetes + Compose | Kubernetes |
| NetBox | Kubernetes + Compose | Kubernetes |
| Netronome | Kubernetes + Compose | Kubernetes |
| Nextcloud AIO | Compose + Kubernetes routing | Compose, Kubernetes |
| Penpot | Compose | Manual |
| Portainer | Kubernetes + Compose | Manual |
| Shared PostgreSQL | Kubernetes + Compose | Kubernetes |
| Monitoring stack | Kubernetes + Compose | Kubernetes |
| RackPeek | Kubernetes + Compose | Kubernetes |
| Reloader | Kubernetes / Helm | Manual |
| Renovate | Kubernetes + Compose | Kubernetes |
| SearXNG | Kubernetes + Compose | Manual |
| Media stack | Compose + Kubernetes routing | Compose, Kubernetes |
| Termix | Kubernetes + Compose | Manual |
| Traefik | Kubernetes + Compose | Kubernetes |
| Uptime Kuma | Kubernetes + Compose | Kubernetes |
| Vaultwarden | Kubernetes + Compose | Kubernetes |
| 3x-ui | Kubernetes | Kubernetes |
Running a Compose stack
Use the service README first. Where a service has an env example, copy it inside
that service's directory and replace the placeholders. The root .env.example
is an older collection of variables, not a complete configuration for every stack.
For example, from the repository root:
cd netbox
cp .env.example .env
$EDITOR .env
docker compose config --quiet
docker compose up -d
docker compose ps
Stacks that attach to proxy require an existing Docker network of that name and
an appropriate reverse proxy. Published host ports still work independently of
Traefik. Check port conflicts before starting an alternative to a Kubernetes
service: DNS, STUN, and HTTP listeners can share the same host.
docker compose down keeps named volumes. Adding -v removes them.
Preparing Kubernetes
The manifests assume Traefik CRDs, cert-manager, and a working storage provisioner. PrometheusRule and ServiceMonitor resources also need the Prometheus Operator. Replace the lab's hosts and addresses before using the configuration elsewhere.
Create a service's namespace, then prepare its ignored Secret from the example. For example:
kubectl apply -f netbox/k8s/namespace.yaml
cp netbox/k8s/secrets.yaml.example netbox/k8s/secrets.yaml
$EDITOR netbox/k8s/secrets.yaml
kubectl apply -f netbox/k8s/secrets.yaml
The deploy workflow applies the tracked resources for marked services. Avoid
applying an entire k8s/ directory blindly: some directories contain Helm values,
examples, and alternative routes. For a manual change, apply the selected manifest
explicitly and check the resulting rollout.
Shared database passwords must agree between the database namespace and each
application's Secret. Updating the PostgreSQL Secret does not change an existing
role's password; see the database README.
Local checks
CI pins its tools in .gitea/workflows/tool-versions.env. Use the same versions:
tools_dir="$(bash .gitea/workflows/install-ci-tools.sh)"
export PATH="$tools_dir:$PATH"
ruff check .
ruff format --check .
actionlint -config-file .gitea/actionlint.yaml .gitea/workflows/*.yaml
.gitea/workflows/sync-renovate-configmap.sh --check
The workflow README lists the rest of the checks. Structure checks do not establish that local Secrets, mounted files, storage, or external services are ready.
Data and recovery
State lives outside Git: PVCs, Docker volumes, bind mounts, databases, and ignored configuration. Keep backups of application data and the keys needed to read it. An image rollback does not roll back database migrations or ConfigMap contents.
Many PVCs use the cluster's default StorageClass; monitoring explicitly uses
local-path. Check the PV reclaim policy before deleting a PVC or namespace.
The manifests do not provide a repository-wide backup schedule.
incident-archive/ contains past incident notes. .docs/storage-audit-instruction.md
is a planning document, not evidence that NFS has been installed.