Saltar a contenido

16 — Backup y restore

Qué hay que respaldar

Componente Crítico Frecuencia recomendada
Base de datos PostgreSQL Diario
backend_django/media/ (uploads) Diario
.env (con secretos) Cada cambio
Código fuente (apps/, backend_django/api/, etc.) ⚠️ Vive en git; backup git suficiente
Builds (apps/*/dist/, static/v3/dist/) Se regeneran con npm run build
node_modules/, venv/ Se regeneran con npm install / pip install

Backup de PostgreSQL

Backup completo (custom format — recomendado)

sudo -u postgres pg_dump \
  -d blimx_saas \
  -F c \
  -Z 9 \
  -f /var/backups/blimx/db-$(date +%Y%m%d-%H%M%S).dump
  • -F c → custom format (comprimido, restaurable selectivamente).
  • -Z 9 → compresión máxima.
  • Tamaño típico: 5-50 MB según volumen de FAQs.

Backup en SQL plano (legible, restore en cualquier Postgres)

sudo -u postgres pg_dump \
  -d blimx_saas \
  --no-owner --no-privileges \
  -f /var/backups/blimx/db-$(date +%Y%m%d-%H%M%S).sql

Cron diario

sudo crontab -u postgres -e

Añade:

# Backup diario a las 3:00 AM, retención 30 días
0 3 * * * pg_dump -d blimx_saas -F c -Z 9 -f /var/backups/blimx/db-$(date +\%Y\%m\%d).dump && find /var/backups/blimx/ -name 'db-*.dump' -mtime +30 -delete

Replica/streaming

Para mayor resiliencia, configura una replica streaming a otro servidor:

# En el primary, en postgresql.conf:
wal_level = replica
max_wal_senders = 3
hot_standby = on

Detalle: https://www.postgresql.org/docs/current/warm-standby.html.

Restore de PostgreSQL

Desde custom format

# Restore en una BD existente (limpia primero las tablas que se restauran)
sudo -u postgres pg_restore \
  -d blimx_saas \
  --clean --if-exists \
  /var/backups/blimx/db-20260524.dump

# Restore en una BD nueva
sudo -u postgres createdb blimx_saas_restore
sudo -u postgres pg_restore \
  -d blimx_saas_restore \
  /var/backups/blimx/db-20260524.dump

Desde SQL plano

sudo -u postgres psql -d blimx_saas -f /var/backups/blimx/db-20260524.sql

Restore parcial (tabla específica)

# Lista las tablas del dump
pg_restore -l /var/backups/blimx/db-20260524.dump | head -40

# Restaura solo una tabla (id en el listing)
pg_restore -L <(pg_restore -l backup.dump | grep "TABLE DATA public bots") \
  -d blimx_saas backup.dump

Backup de uploads (media/)

# rsync incremental — solo copia archivos cambiados
rsync -av --delete \
  /home/blimxapp/saas/chatbot-v3-workspace/backend_django/media/ \
  /var/backups/blimx/media/

Cron diario:

30 3 * * * rsync -av --delete /home/blimxapp/saas/chatbot-v3-workspace/backend_django/media/ /var/backups/blimx/media/

Backup de .env

sudo cp /home/blimxapp/saas/chatbot-v3-workspace/.env /var/backups/blimx/env-$(date +%Y%m%d).bak
sudo chmod 600 /var/backups/blimx/env-*.bak

Cuidado con dónde lo respaldas. Contiene STRIPE_SECRET_KEY, SECRET_KEY, password de la BD. Si lo subes a S3 / Glacier, cifra con KMS o gpg.

Backup off-site (recomendado)

Sube los backups diarios a un bucket externo. Opciones:

Opción 1: AWS S3

aws s3 cp /var/backups/blimx/db-$(date +%Y%m%d).dump s3://my-blimx-backups/$(date +%Y/%m)/ \
  --storage-class GLACIER_IR \
  --sse aws:kms --sse-kms-key-id alias/blimx-backups

Opción 2: rclone (cualquier proveedor)

rclone copy /var/backups/blimx/ remote:blimx-backups/$(date +%Y/%m/%d)/ \
  --transfers 4 --check-first

Drill de restore

Una vez al mes, restaura el backup más reciente en una BD de testing y corre:

sudo -u postgres pg_restore -d blimx_test /var/backups/blimx/db-latest.dump

# Verifica integridad
psql blimx_test -c "SELECT COUNT(*) FROM bots; SELECT COUNT(*) FROM knowledge_base;"
psql blimx_test -c "SELECT MAX(created_at) FROM accounts;"

# Verifica que las FKs no estén rotas
psql blimx_test -c "
SELECT tc.table_name, kcu.column_name, ccu.table_name AS foreign_table
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY';
"

Si todo OK, drop la BD de test:

sudo -u postgres dropdb blimx_test

RTO / RPO recomendados

Métrica Valor recomendado Cómo lograrlo
RPO (Recovery Point Objective) 24h Backup diario
RPO con replica < 1 min Streaming replication
RTO (Recovery Time Objective) < 30 min Backup en mismo data center + script de restore probado
RTO con failover < 5 min Replica + DNS auto-failover

Disaster recovery checklist

Si el servidor primary se pierde por completo:

  1. Provisiona un servidor nuevo con los prereqs de 03-prerrequisitos.md.
  2. Restaura el código: git clone o sube el zip más reciente.
  3. Restaura .env desde tu backup off-site.
  4. Restaura la BD: pg_restore del último dump.
  5. Restaura media/: rsync desde tu backup off-site.
  6. Sigue 04-instalacion.md desde el paso 4 (venv + deps + builds).
  7. Sigue 05-deploy-produccion.md (systemd + nginx + SSL).
  8. Repunta los DNS del dominio al servidor nuevo.
  9. Reconfigura el webhook Stripe con la URL nueva (si cambió).
  10. Smoke test según test/health_check.py.

Tiempo total con backups recientes: 30-60 minutos.

Lo que NO está cubierto por backups

  • Stripe — Stripe es la fuente de verdad de pagos. Si tu BD se corrompe pero Stripe está ok, puedes re-sincronizar suscripciones e invoices con un script que llame a stripe.Subscription.list().
  • OAuth (Google) — los id_token no se respaldan; los usuarios re-autorizan al loguearse.
  • JWT activos — al restaurar, los JWT siguen siendo válidos hasta su expiración (si guardas SECRET_KEY igual). Si quieres invalidarlos a todos, cambia SECRET_KEY y todos los tokens dejan de validar.