homelab/README.md
Alvin Wang e07a5e1dfa Initial commit: k3s homelab infrastructure
Helm charts for media stack (Plex, Sonarr, Radarr, etc.), dashboards
(Glance, Homepage), paperless-ngx, mealie, traefik ingress, MetalLB,
and utilities. Includes SOPS-encrypted secrets and bootstrap script.
2026-04-19 19:22:22 -04:00

153 lines
4.1 KiB
Markdown

# Homelab — k3s Cluster
2-node k3s cluster (1 manager, 1 worker) running a self-hosted homelab stack.
## Architecture
```
Manager Node Worker Node
┌──────────────┐ ┌──────────────┐
│ k3s server │────────────│ k3s agent │
│ Traefik │ │ │
│ Longhorn │ │ Longhorn │
└──────┬───────┘ └──────┬───────┘
│ │
└───────── NFS ─────────────┘
/dogstore
```
**Storage strategy:**
- `/dogstore` (NFS) — mounted on both nodes, used via hostPath for large media/data volumes
- Longhorn — replicated block storage for small config/state volumes
**Ingress:** k3s built-in Traefik with Let's Encrypt via Cloudflare DNS challenge.
**Secrets:** SOPS + age encryption. Secrets live in `secrets/secrets.enc.yaml`, encrypted at rest.
## Services
| Chart | Namespace | Services |
| -------------- | ----------- | -------------------------------------------------------------- |
| traefik-config | kube-system | Traefik HelmChartConfig overlay |
| media | media | Plex, Sonarr, Radarr, Bazarr, Prowlarr, qBittorrent, unpackerr |
| paperless | paperless | Paperless-ngx, Redis, PostgreSQL |
| mealie | apps | Mealie |
| dashboards | apps | Homepage, Glance |
| utils | apps | Zerobyte, Seerr |
## Prerequisites
- Two Linux machines with NFS `/dogstore` mounted on both
- `curl`, `helm`, `kubectl`, `sops`, `age` installed
## Bootstrap
### 1. Install k3s server (manager node)
```bash
./scripts/bootstrap.sh server
```
This prints the worker join command at the end.
### 2. Install k3s agent (worker node)
```bash
K3S_URL="https://<manager-ip>:6443" K3S_TOKEN="<token>" ./scripts/bootstrap.sh agent
```
### 3. Install Longhorn
```bash
./scripts/bootstrap.sh longhorn
```
### 4. Set up SOPS encryption
Generate an age keypair (run on each node):
```bash
./scripts/bootstrap.sh sops-keygen
```
Copy the public key into `.sops.yaml`, replacing the placeholder. Then encrypt your secrets:
```bash
# Edit secrets/secrets.enc.yaml — replace REPLACE_WITH_* placeholders with real values
sops -e -i secrets/secrets.enc.yaml
```
### 5. Apply secrets
```bash
./scripts/bootstrap.sh apply-secrets
```
### 6. Deploy all charts
```bash
./scripts/bootstrap.sh deploy
```
Or deploy individually:
```bash
kubectl create namespace media
helm upgrade --install media charts/media -n media
kubectl create namespace paperless
helm upgrade --install paperless charts/paperless -n paperless
kubectl create namespace apps
helm upgrade --install mealie charts/mealie -n apps
helm upgrade --install dashboards charts/dashboards -n apps
helm upgrade --install utils charts/utils -n apps
# Traefik config goes in kube-system (managed by k3s)
helm upgrade --install traefik-config charts/traefik-config -n kube-system
```
## Verifying
```bash
# Check all pods
kubectl get pods -A
# Check ingress routes
kubectl get ingress -A
# Test a specific service
curl -I https://mealie.ratboo.me
```
## Secret Rotation
1. Decrypt: `sops secrets/secrets.enc.yaml` (opens in `$EDITOR`)
2. Change the values
3. Save and close (SOPS re-encrypts automatically)
4. Apply: `./scripts/bootstrap.sh apply-secrets`
5. Restart affected pods: `kubectl rollout restart deployment/<name> -n <namespace>`
## Repo Structure
```
homelab/
├── README.md
├── .sops.yaml
├── scripts/
│ └── bootstrap.sh
├── charts/
│ ├── traefik-config/
│ ├── media/
│ ├── paperless/
│ ├── mealie/
│ ├── dashboards/
│ └── utils/
└── secrets/
└── secrets.enc.yaml
```