This project stores configurations of services in my homelab.
- Add more nodes for a high-availability setup
- Implement solution for backup to offsite storage
- Include IaC (Infrastructure as Code) for server setup (OS & packages)
- Add and improve documentations
- Add CI/CD to lint and sync the configurations
The homelab runs on a single machine with the following specifications:
- Intel i5-3330
- 16GB RAM (8GB+8GB)
- 960GB SSD (OS +
/mnt/fast) - 1TB HDD (
/mnt/bulk) - Nvidia 1050Ti
The operating system of choice is Debian 13 (trixie), with tailscale installed.
The rest of the host is set up with Ansible (ansible/), which installs:
- a single-node k3s cluster, with the following optional addons disabled:
- helm-controller
- servicelb
- traefik
- local-storage (replaced by a self-managed local-path-provisioner)
- metrics-server
- helm (through Homebrew), used to render charts when bootstrapping Argo CD
Third-party apps/services:
- GitOps solution of choice is combination of kustomize and argo-cd
- No secrets are stored in git. The Tailscale operator OAuth secret is created by hand (see Bootstrap).
- In the Tailscale admin console:
- Enable MagicDNS and HTTPS certificates
- Add
tag:homelab-k3s-operatorandtag:homelab-k3s-ingresstotagOwners, with the operator tag owning the ingress tag - Create an OAuth client for the operator, tagged
tag:homelab-k3s-operator, with the scopes listed in the operator setup guide (at least Devices Core and Auth Keys, write)
- Set up the host. This needs Ansible and Homebrew installed on the host first.
Debian's
ansiblepackage includes thecommunity.generalcollection; with plainansible-core, runansible-galaxy collection install -r requirements.yamlas well. Add--connection=localwhen running on the host itself:sudo apt install ansible cd ansible && ansible-playbook site.yaml --ask-become-pass - Create the Tailscale operator OAuth secret:
kubectl create namespace tailscale kubectl -n tailscale create secret generic operator-oauth \ --from-literal=client_id=... --from-literal=client_secret=... - Install Argo CD, then the ApplicationSet that creates one application per directory under
kustomize/:kubectl kustomize --enable-helm kustomize/argocd | kubectl apply --server-side -f - kubectl apply -k kustomize/homelab - Open the Argo CD UI (
kubectl -n argocd port-forward svc/argocd-server 8080:80, useradmin, password fromkubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d) and synclocal-path-provisionerandtailscalefirst, then the other applications. Oncetailscaleis synced, Argo CD is also reachable athttps://argocd.<tailnet>.ts.net.
All endpoints are private and only reachable over Tailscale.
Each Ingress uses the tailscale ingress class from the Tailscale operator,
which gives the service its own tailnet device at https://<name>.<tailnet>.ts.net with a certificate issued by Tailscale.
MagicDNS and HTTPS must be enabled for the tailnet.
Volumes are provisioned by local-path-provisioner into <disk>/k8s/<namespace>/<pvc>/, with reclaimPolicy: Retain:
local-fast(default):/mnt/faston the SSD, for app configlocal-bulk:/mnt/bulkon the HDD, for media (themediaPVC shared by jellyfin and qbittorrent)