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>
66 lines
3.8 KiB
Bash
Executable File
66 lines
3.8 KiB
Bash
Executable File
#!/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'
|