A personal lab where I experiment with cloud infrastructure in a dedicated environment I fully control through OVH — provisioned with OpenTofu, orchestrated with k3s, and managed end-to-end via GitOps.
graph TD
dev["💻 Developer"]
subgraph local["Local Machine"]
tooling["DockerTooling\nkubectl · helm · tofu · sops"]
age["age key"]
kubeconfig["kubeconfig"]
end
subgraph github["GitHub"]
homelab_repo["Homelab repo\n(this repo)"]
docker_repo["DockerTooling repo"]
ghcr["GHCR\nk8s-tooling image"]
end
subgraph ovh["OVH"]
dns["DNS\n*.victor-malod.ovh"]
s3["Object Storage\nTofu state"]
subgraph vps["VPS · Ubuntu 24.04 · k3s"]
argocd["ArgoCD\n(App of Apps)"]
helm_secrets["helm-secrets\n+ SOPS + age"]
cert_manager["cert-manager\n+ OVH webhook"]
traefik["Traefik\n(ingress)"]
tls_secret["Wildcard TLS cert"]
authelia["Authelia\n(OIDC + ForwardAuth)"]
end
end
subgraph letsencrypt["Let's Encrypt"]
acme["ACME v2"]
end
dev -->|"push"| homelab_repo
dev -->|"push"| docker_repo
docker_repo -->|"CI builds & pushes"| ghcr
age -->|"decrypt secrets"| tooling
kubeconfig -->|"cluster access"| tooling
tooling -->|"tofu apply"| vps
tooling -->|"tofu apply"| dns
tooling -->|"state"| s3
homelab_repo -->|"GitOps sync"| argocd
argocd -->|"decrypts secrets"| helm_secrets
argocd -->|"deploys"| cert_manager
argocd -->|"deploys"| traefik
argocd -->|"deploys"| authelia
cert_manager -->|"DNS-01 via OVH API"| dns
acme -->|"verifies TXT"| dns
acme -->|"issues cert"| cert_manager
cert_manager -->|"stores"| tls_secret
traefik -->|"serves TLS"| tls_secret
authelia -->|"OIDC SSO"| argocd
traefik -->|"ForwardAuth"| authelia
Homelab/
├── docker/ # Custom Docker images
│ └── argocd-repo-server/ # ArgoCD repo-server with helm-secrets, sops, age
├── terraform/ # OpenTofu — OVH VPS, DNS, k3s provisioning
├── argocd/ # ArgoCD Application manifests (App of Apps)
├── helm/ # Helm charts and values per app
│ ├── argocd-config/ # ArgoCD server config (OIDC, RBAC, helm-secrets, IngressRoute)
│ ├── authelia/ # Authelia config + SOPS-encrypted secrets (OIDC, session, storage)
│ ├── authelia-users/ # Authelia users database (SOPS-encrypted)
│ ├── cert-manager/
│ ├── cert-manager-webhook-ovh/
│ ├── cluster-issuers/
│ ├── ovh-credentials/ # OVH API secret (SOPS-encrypted values)
│ └── traefik/
├── bootstrap/ # One-time bootstrap manifests and patches
└── BOOTSTRAP.md # Step-by-step provisioning guide
See BOOTSTRAP.md for the full provisioning guide.
Conventional commits are enforced locally via a commit-msg hook available in .githooks/. Run this once after cloning:
git config core.hooksPath .githooks