respaldo: Storage Box BX11 en Hetzner — no dependemos más de un laptop
El usuario pidió respaldar en «el volumen, aunque sea montándolo aquí». No se puede: un HC Volume es un dispositivo de bloque por RED, sólo se adjunta a servidores de Hetzner del mismo DC, y sólo a uno a la vez. harkaq-cosecha es el disco del worker efímero y vvv está al 78%. El producto correcto es un Storage Box: se monta desde el laptop (SSHFS/CIFS) y habla rsync/borg/restic por SSH. BX11 = 1 TiB, €3,20/mes, sin alta. Creado en hel1 con protección de borrado y la clave github5. rsync plano y no borg: el store es CAS, los ficheros son inmutables y se nombran por hash, así que incremental es exactamente lo correcto y no hay repo ni claves que mantener. borg comprimiría 4x (79% del store es .debug_) pero 126 G en 1 TiB no aprieta. El store va SIN --delete a propósito: un respaldo que replica los borrados no protege del borrado por error, y store-gc.sh acaba de demostrar que puede equivocarse en silencio. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Semántico sayk'uy
Mana ima sutichaypas t'ikrakurqanchu: qillqalla, yachachiylla utaq willaylla t'ikrakurqan.
1 qillqakuna · +65 −0
diff --git a/scripts/respaldo-storagebox.sh b/scripts/respaldo-storagebox.sh
new file mode 100755
index 00000000..02c06d6e
--- /dev/null
+++ b/scripts/respaldo-storagebox.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Respaldo de hammer al Storage Box de Hetzner (BX11, 1 TiB, hel1).
+#
+# ── POR QUÉ UN STORAGE BOX Y NO EL VOLUMEN ──────────────────────────────────────────────────────
+# El usuario pidió respaldar «en el volumen, aunque sea montándolo aquí». **No se puede**: un Hetzner
+# Cloud Volume es un dispositivo de bloque por RED que sólo se adjunta a servidores de Hetzner Cloud
+# del mismo datacenter — no se monta en un laptop, y encima sólo puede estar en UN servidor a la vez.
+# `harkaq-cosecha` (100 G) es el disco del worker efímero y `vvv` (260 G, en gioser) está al 78%.
+# El Storage Box SÍ es el producto para esto: se monta desde acá (SSHFS/CIFS) y habla rsync/borg/
+# restic por SSH. BX11 = 1 TiB por €3,20/mes, sin coste de alta. Ver [[capacidad-disco-proyeccion]].
+#
+# ── POR QUÉ rsync PLANO Y NO borg/restic ────────────────────────────────────────────────────────
+# El store es CAS: los ficheros son INMUTABLES y se nombran por hash. Nunca cambian, sólo aparecen o
+# desaparecen. Para eso rsync incremental es exactamente lo correcto y no hay que mantener repos ni
+# claves de cifrado. borg comprimiría 4x (el 79% del store es `.debug_`), pero 126 G en 1 TiB no
+# aprieta a nadie: no vale la complejidad todavía. Si algún día aprieta, ahí sí borg.
+#
+# ── EL STORE NO SE BORRA EN EL DESTINO, A PROPÓSITO ─────────────────────────────────────────────
+# `--delete` NO va sobre el store. Un respaldo que replica los borrados no protege del borrado por
+# error, y el 2026-08-07 `store-gc.sh` demostró que puede equivocarse EN SILENCIO (reportó 364
+# artefactos borrados sin haber borrado ninguno). El respaldo acumula; podarlo es una decisión
+# deliberada y aparte. El repo sí va con `--delete`, que para eso está git.
+#
+# Uso: scripts/respaldo-storagebox.sh [--seco]
+set -eu
+
+SB_USER="${SB_USER:-u647150}"
+SB_HOST="${SB_HOST:-u647150.your-storagebox.de}"
+SB_PORT="${SB_PORT:-23}" # 23 = SSH completo (rsync). El 22 sólo da SFTP/SCP restringido.
+KEY="${KEY:-$HOME/.ssh/github5}"
+RAIZ="${RAIZ:-/home/sergio/hammer}"
+
+SECO=""
+[ "${1:-}" = "--seco" ] && SECO="--dry-run"
+
+SSH_CMD="ssh -p $SB_PORT -i $KEY -o StrictHostKeyChecking=accept-new"
+
+if ! $SSH_CMD "$SB_USER@$SB_HOST" true 2>/dev/null; then
+ echo "!! No hay SSH al Storage Box ($SB_HOST:$SB_PORT)."
+ echo "!! Si acabás de crearlo, el DNS tarda unos minutos en propagar. Reintentá."
+ exit 1
+fi
+
+echo "==> destino: $SB_USER@$SB_HOST:$SB_PORT ${SECO:+(SECO)}"
+$SSH_CMD "$SB_USER@$SB_HOST" 'mkdir -p hammer/store hammer/repo hammer/estado' 2>/dev/null || true
+
+# 1. EL STORE — lo caro e irreemplazable (meses de CPU). Sin --delete, ver cabecera.
+echo "==> store"
+rsync -a --info=progress2 --partial $SECO -e "$SSH_CMD" \
+ "$RAIZ/store/" "$SB_USER@$SB_HOST:hammer/store/"
+
+# 2. EL REPO — barato, y ya está espejado a GitHub privado; va igual para tener todo en un sitio.
+# Se excluye lo regenerable y lo gigante: store (arriba), work, target, .dev-fs.
+echo "==> repo"
+rsync -az --delete $SECO -e "$SSH_CMD" \
+ --exclude /store --exclude /work --exclude /target --exclude /.dev-fs \
+ --exclude /dist --exclude /.scratch \
+ "$RAIZ/" "$SB_USER@$SB_HOST:hammer/repo/"
+
+# 3. El grafo de estado, aparte, para poder mirar qué había sin desempacar nada.
+echo "==> estado"
+rsync -az $SECO -e "$SSH_CMD" "$RAIZ/docs/state/" "$SB_USER@$SB_HOST:hammer/estado/" 2>/dev/null || true
+
+echo "==> ocupación en el Storage Box:"
+$SSH_CMD "$SB_USER@$SB_HOST" 'df -h . 2>/dev/null | tail -1; du -sh hammer/* 2>/dev/null'