Merge PR #15: RESTORE.md + prueba E2E de restauración
ci / lint-test-leaks (push) Canceled after 0s
ci / lint-test-leaks (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,145 @@
|
|||||||
|
# RESTORE.md — Restauración de CayceOps desde backups cifrados
|
||||||
|
|
||||||
|
**Modelo:** la VPS genera backups cifrados (age) en `/var/backups/cayce/YYYY-MM-DD/`;
|
||||||
|
tu Mac los descarga con el usuario `backup-pull` (solo lectura). La clave
|
||||||
|
**privada** de age vive SOLO en tu Mac. Este runbook asume una VPS nueva
|
||||||
|
(Ubuntu + IP apuntada por DNS) y tus backups descifrados a mano.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Descargar y descifrar (en TU Mac — nunca en la VPS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# pull (clave restringida: solo lectura de /var/backups/cayce)
|
||||||
|
rsync -av --partial backup-pull@15.235.3.239:/ ~/backups/cayce/
|
||||||
|
|
||||||
|
# integridad (sin clave privada; manifest lista los artefactos CIFRADOS)
|
||||||
|
cd ~/backups/cayce/2026-XX-XX && shasum -a 256 -c manifest.sha256
|
||||||
|
# (Linux: sha256sum -c manifest.sha256)
|
||||||
|
|
||||||
|
# descifrar (clave privada age del operador — la que NO está en la VPS)
|
||||||
|
age -d -i ~/keys/cayce-backup.txt -o cayce-ops-db.dump cayce-ops-db.dump.age
|
||||||
|
age -d -i ~/keys/cayce-backup.txt -o gitea-dump.zip gitea-dump.zip.age
|
||||||
|
age -d -i ~/keys/cayce-backup.txt -o config.tar.gz config.tar.gz.age
|
||||||
|
```
|
||||||
|
|
||||||
|
Artefactos:
|
||||||
|
| Archivo | Contenido | Formato |
|
||||||
|
|---|---|---|
|
||||||
|
| `cayce-ops-db.dump` | BD de CayceOps | `pg_dump` custom (restaurar con `pg_restore`) |
|
||||||
|
| `gitea-dump.zip` | repos + sqlite + adjuntos + config Gitea | zip de `gitea dump` |
|
||||||
|
| `config.tar.gz` | `caddy/` (Caddyfile+Caddyfile.d), `gitea/` (app.ini + internal_token), `systemd/` (unidades cayce-*), `cayce-ops/dot-env` | tar.gz |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. VPS nueva — base del sistema
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y postgresql age rsync git
|
||||||
|
# Gitea: misma versión mayor que la VPS origen (verSTEP: gitea --version en el viejo
|
||||||
|
# servidor ANTES de apagarlo, o lee la versión del zip gitea-dump: gitea-dump zip
|
||||||
|
# contiene un archivo "app.ini" con la versión en comentarios... anota la versión
|
||||||
|
# manualmente; el binario se baja de https://dl.gitea.com/gitea/)
|
||||||
|
adduser --system --group --home /var/lib/gitea git
|
||||||
|
mkdir -p /etc/gitea /var/lib/gitea /etc/cayce-backup
|
||||||
|
curl -L "https://dl.gitea.com/gitea/<versión>/gitea-<versión>-linux-amd64" -o /usr/local/bin/gitea
|
||||||
|
chmod +x /usr/local/bin/gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Postgres
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl enable --now postgresql
|
||||||
|
sudo -u postgres psql <<SQL
|
||||||
|
CREATE ROLE cayce LOGIN PASSWORD '<password-del-.env-restaurado>';
|
||||||
|
CREATE DATABASE cayce_ops OWNER cayce;
|
||||||
|
SQL
|
||||||
|
|
||||||
|
# restaurar el dump (los ficheros descifrados son legibles solo por ti;
|
||||||
|
# cópiales permisos de lectura para postgres o pásalos por stdin)
|
||||||
|
sudo -u postgres pg_restore -d cayce_ops --no-owner --no-privileges \
|
||||||
|
/ruta/cayce-ops-db.dump
|
||||||
|
|
||||||
|
# verificación
|
||||||
|
sudo -u postgres psql -d cayce_ops -tAc \
|
||||||
|
"SELECT count(*) FROM audit_log;" # debe coincidir con la última ancla
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Gitea
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# config restaurada desde config.tar.gz
|
||||||
|
tar -xzf config.tar.gz -C /tmp/restored
|
||||||
|
cp /tmp/restored/gitea/app.ini /etc/gitea/app.ini
|
||||||
|
chown root:git /etc/gitea/app.ini && chmod 660 /etc/gitea/app.ini
|
||||||
|
cp /tmp/restored/gitea/internal_token /etc/gitea/ && chown git:git /etc/gitea/internal_token
|
||||||
|
|
||||||
|
# NOTA sobre ROOT_URL: app.ini restaurado apunta a https://git.cayce-co.xyz/ —
|
||||||
|
# el DNS de ese subdominio debe existir ANTES de iniciar Gitea o las URLs
|
||||||
|
# absolutas (webhooks, notificaciones) quedarán mal.
|
||||||
|
|
||||||
|
# dump de Gitea: contiene data/, repos/ y custom/. Restaurar SOBRE el dump
|
||||||
|
# de Gitea exige la misma versión del binario; descomprimir dentro de WORK_PATH
|
||||||
|
systemctl stop gitea 2>/dev/null || true
|
||||||
|
unzip -o gitea-dump.zip -d /tmp/gitea-restore
|
||||||
|
rsync -a /tmp/gitea-restore/data/ /var/lib/gitea/data/
|
||||||
|
rsync -a /tmp/gitea-restore/repos/ /var/lib/gitea/data/gitea-repositories/ 2>/dev/null || true
|
||||||
|
rsync -a /tmp/gitea-restore/custom/ /var/lib/gitea/custom/ 2>/dev/null || true
|
||||||
|
chown -R git:git /var/lib/gitea
|
||||||
|
sudo -u git /usr/local/bin/gitea migrate -c /etc/gitea/app.ini # ajusta esquema si cambia versión
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Consistencia:** los dumps de Gitea se toman EN CALIENTE (el servicio sigue
|
||||||
|
> corriendo). Riesgo teórico de inconsistencia sqlite/repos si un push ocurre
|
||||||
|
> en el mismo instante. Para un backup garantizado-consistente: `systemctl stop
|
||||||
|
> gitea` antes de `gitea dump` y volver a levantar después (no automatizado a
|
||||||
|
> propósito: no queremos ventanas de downtime diarias).
|
||||||
|
|
||||||
|
## 4. Config del sistema (Caddy, unidades systemd, .env)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Caddy
|
||||||
|
apt-get install -y caddy # o el instalador oficial
|
||||||
|
rsync -a /tmp/restored/caddy/Caddyfile /etc/caddy/Caddyfile
|
||||||
|
rsync -a /tmp/restored/caddy/Caddyfile.d/ /etc/caddy/Caddyfile.d/
|
||||||
|
systemctl enable --now caddy # emitirá certificados si el DNS ya apunta aquí
|
||||||
|
|
||||||
|
# unidades systemd de cayce (DESHABILITADAS por diseño — ver riesgos)
|
||||||
|
rsync -a /tmp/restored/systemd/ /etc/systemd/system/
|
||||||
|
systemctl daemon-reload
|
||||||
|
# NO habilitar cayce-ops@*.timer sin el operador
|
||||||
|
|
||||||
|
# .env de cayce-ops
|
||||||
|
install -d -m 755 /home/ubuntu
|
||||||
|
rsync -a /tmp/restored/cayce-ops/dot-env /home/ubuntu/cayce-ops/.env
|
||||||
|
chown ubuntu:ubuntu /home/ubuntu/cayce-ops/.env && chmod 660 /home/ubuntu/cayce-ops/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Código del repo
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u ubuntu git clone http://127.0.0.1:3100/cayce/cayce-ops.git /home/ubuntu/cayce-ops \
|
||||||
|
|| git clone https://git.cayce-co.xyz/cayce/cayce-ops.git /home/ubuntu/cayce-ops
|
||||||
|
cd /home/ubuntu/cayce-ops && uv sync
|
||||||
|
make check # gate verde antes de considerar la restauración completa
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Reinstalar el pipeline de backup en la VPS nueva
|
||||||
|
|
||||||
|
```bash
|
||||||
|
install -m 700 -o root -g root deploy/backup/make-backup.sh /usr/local/bin/cayce-make-backup
|
||||||
|
install -m 644 deploy/systemd/cayce-backup.{service,timer} /etc/systemd/system/
|
||||||
|
systemctl daemon-reload && systemctl enable --now cayce-backup.timer
|
||||||
|
# la MISMA clave pública age → tu Mac sigue pudiendo descifrar:
|
||||||
|
echo 'age1<tu-pubkey>' > /etc/cayce-backup/age-recipient.pub
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Checklist de verificación post-restauración
|
||||||
|
|
||||||
|
- [ ] `sha256sum -c manifest.sha256` OK en tu Mac (antes de descifrar)
|
||||||
|
- [ ] `pg_restore --list` del dump sin errores
|
||||||
|
- [ ] `verify_audit_chain(sess)` → `(True, None)` contra la BD restaurada
|
||||||
|
- [ ] Gitea responde por TLS en `git.cayce-co.xyz` y `git rev-parse main` da el commit esperado
|
||||||
|
- [ ] `make check` verde en el repo restaurado
|
||||||
|
- [ ] Primer backup nuevo generado y verificado desde la Mac
|
||||||
Reference in New Issue
Block a user