The IaC system for my homelab and other devices.
vps0is a cloud VPS that uses Docker Compose to run public-facing services likeapps.obtainium.imranr.devand tunnel some requests through tosrv0.srv0is a lightweight home server that uses Kubernetes (K3s) to run personal services like Immich.bigpcis a gaming PC that also serves as a Kubernetes worker node for GPU-accelerated workloads like Ollama.pcis a laptop that runs Syncthing (via Docker Compose) to sync files tosrv0.rpiis an SBC that streams a live camera feed to Frigate onsrv0.
- Infrastructure as Code: Everything should be declarative and automated, using standard tooling wherever possible. Custom scripts should be minimal and only where necessary.
- Security: As the codebase is public and the system runs public-facing services containing highly personal data, security must be taken seriously. To that end:
- Authelia SSO guards every service that needs it.
- CrowdSec automated threat response guards all public services.
- Geoblocking is used for services that do not need to be globally accessible.
- Network policies are used in the
srv0Kubernetes stack to ensure that pod-to-pod communication is only allowed where necessary. - WireGuard key pairs (as opposed to symmetric token-based encryption) protect the public-exposure tunnel between
srv0andvps0; each peer authenticates with its own key, preventing certain kinds of MITM attacks. - The Principle of Least Privilege is applied to containers, with elevated privileges and root runtime user only allowed where necessary. Host devices are granted as Kubernetes device-plugin resources (via the generic-device-plugin) rather than
privileged: true. - Comprehensive Monitoring and Alerting is done using Alloy + Prometheus, Loki, Grafana, Ntfy.sh + Logtfy, Headlamp, Dozzle, and Uptime Kuma.
- Falco flags suspicious activity on K3s nodes.
- A Honeypot (Opencanary) is used to discover intruders.
- Regular update checking is done via Renovate: app dependency PRs auto-merge when their test gate passes, while Infra digest/chart PRs are reviewed and merged manually.
# Install prerequisites on every machine
bash scripts/prereqs.sh
# Create the gitignored config tree (never overwrites existing files).
# On srv0, --detect fills MY_UID/GPU_PROFILE/HA_CONBEE/HA_BLUETOOTH.
bash scripts/init-config.sh srv0 --detect
bash scripts/init-config.sh vps0
# Fill config/VARS.env, values/compose envs, Authelia users/rules, and the
# optional vps0 agent config. See docs/configuration.md.
bash scripts/validate.sh srv0
bash scripts/validate.sh vps0
# Deploy one target; srv0 uses Helm, the rest use the Compose wrapper.
bash scripts/deploy.sh srv0
bash scripts/deploy.sh vps0
bash scripts/deploy.sh pc
# Or run Compose directly through the wrapper (env files, machine facts,
# private overlay, profiles, and vps0 Authelia render are automatic).
bash scripts/compose.sh vps0 up -d
bash scripts/compose.sh vps0 logs -f authelia
# Run Renovate manually (the in-cluster jobs do this on a schedule) — machine-local
bash scripts/renovate.sh [apps|infra|all|clear-cache] [--dry-run]Detailed documentation lives in docs/; start with
docs/runbooks/first-boot.md for the end-to-end
install, then docs/configuration.md for the complete
config surface (index in AGENTS.md). Note that while LLMs are used in development, the LLM isn't the one putting its data on the line. It is just a tool and is used like one.