Files
k8s-manifests/backup-system/RESTORE.md
T
chemavxandClaude Fable 5 c364d46ac6 feat(backup-system): segundo offsite Backblaze B2 (crown jewels)
- b2-crown-jewels.sh: sync diario 04:00 de las 2 copias mas recientes de
  cada servicio irremplazable (todo menos uptime-kuma) a
  b2:chemavx-k3s-backups/crown-jewels/ (~2GB, tier gratuito).
- reddit-intel.sh sube tambien a B2 (retencion 3d).
- verify.sh comprueba Mega (completo) + B2 (crown jewels).
- Config via Secret out-of-band rclone-conf-b2 (mega+b2, kubectl, NO git);
  consolidar en Infisical RCLONE_CONF cuando se anada [b2] por UI (la
  identity del operator es read-only por API).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 17:24:02 +00:00

5.7 KiB

RESTORE.md — Runbook de restauración del homelab

Última revisión: 2026-07-15. Si cambias backup.sh, actualiza este runbook.

Dónde están las copias

  • Mega (mega:k3s-backups/): espejo diario de /data/backups/backups del master (retención 7 por servicio; 3 para uptime-kuma y home-master), más el subdir reddit-intel/ que sube el CronJob de n97.
  • Backblaze B2 (b2:chemavx-k3s-backups/crown-jewels/ + reddit-intel/): copia reducida "crown jewels" (últimas 2 de cada servicio irremplazable, todo menos uptime-kuma). Segundo proveedor por si Mega falla.
  • Acceso: credenciales rclone en Infisical (/backup-system, key RCLONE_CONF). Si el cluster está muerto, Infisical también → usa el login de Mega/B2 de la cuenta personal (Vaultwarden... que también está en el backup: guarda estas dos contraseñas TAMBIÉN en un gestor externo al homelab, p. ej. el llavero del móvil).

⚠️ La cadena de dependencias (leer antes de restaurar nada)

token k3s ──> state.db (todos los Secrets k8s) ──> infisical-secrets (ENCRYPTION_KEY)
                                                        │
                                                        v
                                            dump infisical-pg (secrets de apps)
                                                        │
                                                        v
                                  resto de apps (n8n, ghost smtp, ddns, runner…)
  1. k3s-db_*.tar.gz contiene state.db + /var/lib/rancher/k3s/server/token + /etc/rancher/k3s/. Sin ese token, un k3s nuevo NO puede leer el state.db (los datos de bootstrap van cifrados con él).
  2. El Secret infisical-secrets (ns infisical: ENCRYPTION_KEY, AUTH_SECRET) está DENTRO de state.db. Sin él, el dump infisical-pg es indescifrable.
  3. n8n es autosuficiente: su encryptionKey va dentro de n8n_*.tar.gz (.n8n/config).

Escenario A — Perder un PVC / una app (lo habitual)

Restaurar solo el artefacto de esa app (ver tabla). El cluster sigue vivo.

Escenario B — Muere el disco del master (chemavx-k8)

  1. Reinstalar Ubuntu + k3s server (misma versión mayor; ver skill k8s-infra).
  2. Restaurar del k3s-db_*.tar.gz: /etc/rancher/k3s/, el fichero token en /var/lib/rancher/k3s/server/token y state.db* en /var/lib/rancher/k3s/server/db/ (con k3s parado). Arrancar k3s.
  3. Con el API server vivo: los manifests los trae ArgoCD desde Gitea → pero Gitea está en el master: restaurar primero Gitea (tabla) para que ArgoCD sincronice.
  4. Restaurar los datos de apps del master (tabla). Reinstalar Tailscale a mano (está fuera de k8s).

Escenario C — Muere el disco del worker (n97)

Reinstalar Ubuntu + k3s agent (token del master), dejar que los pods se reprogramen y restaurar: ghost-en, zona-exclusion, researchowl, trilium, umami-pg, roswell-pg (la BD corre en n97) y /opt/reddit-intel + Docker.

Tabla de restauración por artefacto

Artefacto Cómo restaurar
n8n_*.tar.gz Extraer en /data/n8n (hostPath master), reiniciar deploy. Incluye encryptionKey.
openclaw_*.tar.gz Extraer en el PVC openclaw-pvc (pod parado).
homarr_*.tar.gz db/db.sqlite → PVC db; redis/dump.rdb → PVC redis.
authentik-pg_*.sql.gz gunzip -c | kubectl exec -i postgresql-0 -n authentik -- psql -U authentik authentik (BD vacía primero).
grafana_*.tar.gz grafana.db → PVC de grafana, reiniciar pod.
k3s-db_*.tar.gz Ver Escenario B. No restaurar sobre un cluster sano.
gitea_*.tar.gz Extraer en el PVC de gitea; renombrar gitea/gitea-backup.dbgitea/gitea.db. El registry (packages) NO está: re-push de imágenes vía CI (re-run de Gitea Actions por app).
ghost-*-db_*.db.gz gunzipcontent/data/ghost.db (pod parado).
ghost-*-content_*.tar.gz Extraer en /var/lib/ghost/content (incluye imágenes, temas, data/redirects.yaml; el data/ghost.db del tar es copia en caliente — usa el -db_*.db.gz, que es la consistente).
researchowl_*.db.gz gunzip/data/researchowl.db en el PVC (pod parado; borrar -wal/-shm viejos).
roswell-pg_*.sql.gz / umami-pg_*.sql.gz Como authentik: psql contra el deploy/postgres de su namespace.
infisical-pg_*.sql.gz Primero debe existir el Secret infisical-secrets original (viene en state.db; si no, exportarlo ANTES de perderlo). Luego psql contra infisicalDB en postgresql-0.
trilium_*.tar.gz Extraer en /home/node/trilium-data (PVC, pod parado).
vaultwarden_*.tar.gz Extraer en el PVC (pod parado). Incluye db, attachments y claves RSA.
uptime-kuma_*.db.gz gunzip/app/data/kuma.db (pod parado, borrar -wal/-shm).
filebrowser-db_*.tar.gz Extraer en el PVC filebrowser-db.
home-master_*.tar.gz Extraer en /home/chemavx. No incluye ~/.ssh (regenerar claves) ni ~/bin ni venvs/caches (reinstalar).
reddit-intel/reddit-intel_*.tar.gz Extraer en /opt/reddit-intel de n97, docker compose up -d.

Qué NO está en el backup (reconstruible, asumido)

  • Registry de imágenes de Gitea (re-build por CI), modelos Ollama (re-pull), hf-cache de roswell, Prometheus TSDB (histórico de métricas se pierde), registry-cache, SO de los nodos, Tailscale (re-join), certificados TLS (cert-manager los re-emite), DNS (favonia lo reconstruye).
  • ~/.ssh del master: excluido a propósito — regenerar par ed25519 y re-autorizar en n97/Gitea.

Simulacro

Tras cualquier cambio gordo en backup.sh, repetir el simulacro: bajar de Mega el ghost-en-db más reciente, PRAGMA integrity_check + SELECT count(*) FROM posts, y extraer un home-master en /tmp comprobando que ~/.claude/ está dentro.