Volver a la wiki

Disaster Recovery — CreaRack Pro

Disaster Recovery — CreaRack Pro

Fecha: 07-04-2026 · Actualizado: 02-07-2026 (auditoría s185 — lista de secrets sincronizada con compose.prod.yml) Objetivo: Restaurar CreaRack Pro desde cero en un servidor nuevo Tiempo estimado: 45-60 minutos (con backups disponibles) Audiencia: Edu, Dani


Requisitos previos

RecursoDónde encontrarlo
Backup PostgreSQL (.sql.gz)Hetzner Object Storage: crearack-backups-lock/postgres/ (desde el 24-09-2026; depósito con bloqueo de borrado de 30 días. El antiguo crearack-backups se vacía hacia el 24-10-2026)
Código fuenteGitHub: CreaRackSL/CreaRack-Pro
Variables de entorno (12 secrets)Panel Dokploy → Compose → Environment
Certificados SSLAuto-generados por Let’s Encrypt (no hay que restaurar)
Media files (stencils, signage)Docker volume app_media (654 MB) — sin backup offsite actualmente
DNSCloudflare → apuntar A record a la nueva IP

Secrets necesarios (guardar en lugar seguro)

Fuente de verdad: las variables declaradas en compose.prod.yml (servicio web/worker). Si esta tabla y el compose divergen, manda el compose.

VariableDescripción
DJANGO_SECRET_KEYClave criptográfica Django
POSTGRES_PASSWORDPassword PostgreSQL
REDIS_PASSWORDPassword Valkey
CREDENTIAL_ENCRYPTION_KEYCifrado at-rest de credenciales de dispositivos (¡distinta a propósito en STAGE vs PROD!)
GEMINI_API_KEYAPI key Google AI Studio (Gemma — Regla 8)
ANTHROPIC_API_KEYAPI key Anthropic (fallback del router IA; puede estar vacía)
RESEND_API_KEYAPI key Resend (email)
GITHUB_TOKENToken GitHub (deploys)
WORKSPACE_API_KEYIntegración con el workspace
WORKSPACE_MCP_TOKENToken MCP del workspace
CF_ACCESS_CLIENT_SECRETService token CF Access
INTERNAL_TOOLS_TOKENAuth de herramientas internas

DEEPSEEK_API_KEY — eliminada (proveedor retirado, key revocada el 16-05-2026; Regla 8 = solo Gemma vía Google AI Studio).

IMPORTANTE: Estos secrets solo están en el panel Dokploy. Si pierdes el servidor sin haberlos respaldado, necesitarás regenerar todos.


Paso 1 — Servidor nuevo Hetzner (10 min)

  1. Hetzner Cloud Console → Create Server
  2. Configuración:
    • OS: Ubuntu 24.04 LTS
    • Tipo: CCX (dedicated vCPU) — mínimo 4 vCPU / 16 GB RAM
    • Datacenter: eu-central (Falkenstein o Nuremberg)
    • SSH Key: añadir tu clave pública Ed25519
    • Firewall: aplicar reglas existentes (22, 80, 443)
    • Backups: activar desde el inicio
  3. Anotar la IP pública del nuevo servidor

O restaurar desde snapshot

Si tienes un snapshot reciente de Hetzner:

  1. Hetzner Cloud Console → Snapshots → seleccionar el más reciente
  2. Create Server from Snapshot
  3. Verificar que todo arranca: docker ps, curl localhost:8000/health
  4. Actualizar DNS en Cloudflare
  5. FIN — no necesitas el resto de pasos

Paso 2 — Setup base del servidor (10 min)

# Conectar al nuevo servidor
ssh root@<NUEVA_IP>

# Actualizar sistema
apt update && apt upgrade -y

# Instalar dependencias
apt install -y fail2ban netfilter-persistent iptables-persistent rclone

# Configurar SSH (si no viene del snapshot)
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd

# Crear usuario con acceso SSH
# (o verificar que tu clave pública está en /root/.ssh/authorized_keys si usas root)

Paso 3 — Docker + Dokploy (10 min)

# Instalar Docker
curl -fsSL https://get.docker.com | sh

# Verificar
docker --version
docker compose version

# Instalar Dokploy (esto inicializa Docker Swarm automáticamente)
curl -sSL https://dokploy.com/install.sh | sh

# Verificar Dokploy
docker service ls
# Debe mostrar: dokploy, dokploy-postgres, dokploy-redis

Configurar Dokploy

  1. Abrir http://<NUEVA_IP>:3000 en el navegador
  2. Crear cuenta admin
  3. Projects → Create → tipo Compose
  4. Conectar con GitHub repo CreaRackSL/CreaRack-Pro
  5. Compose file: compose.prod.yml
  6. Environment: añadir las 12 variables secretas + las públicas:
# Públicas
DJANGO_SETTINGS_MODULE=config.settings.production
DJANGO_ALLOWED_HOSTS=crearack.com,www.crearack.com,localhost,<NUEVA_IP>
CSRF_TRUSTED_ORIGINS=https://crearack.com,https://www.crearack.com
POSTGRES_HOST=db
POSTGRES_PORT=5432
POSTGRES_DB=crearack_pro
POSTGRES_USER=crearack_user
VICTORIAMETRICS_URL=http://victoriametrics:8428
MIB_CACHE_DIR=/app/mib_cache

# Secrets (reemplazar con valores reales — lista completa en la tabla de arriba)
DJANGO_SECRET_KEY=<valor>
POSTGRES_PASSWORD=<valor>
REDIS_PASSWORD=<valor>
CREDENTIAL_ENCRYPTION_KEY=<valor>
GEMINI_API_KEY=<valor>
ANTHROPIC_API_KEY=<valor>
RESEND_API_KEY=<valor>
GITHUB_TOKEN=<valor>
WORKSPACE_API_KEY=<valor>
WORKSPACE_MCP_TOKEN=<valor>
CF_ACCESS_CLIENT_SECRET=<valor>
INTERNAL_TOOLS_TOKEN=<valor>
  1. Deploy — esperar a que todos los contenedores arranquen

Paso 4 — Restaurar base de datos (5 min)

# Descargar último backup del Object Storage
mkdir -p /opt/backups/postgres
rclone copy hetzner:crearack-backups-lock/postgres/ /opt/backups/postgres/ --include "*$(date +%Y-%m-%d)*"

# Si no hay backup de hoy, listar disponibles:
rclone ls hetzner:crearack-backups-lock/postgres/

# Si alguien "borró" copias, siguen como versiones ocultas durante 30 días (bloqueo)
# y 7 más tras marcarse como borradas: listarlas y recuperarlas con la herramienta de Amazon
#   /opt/backups/s3api.sh s3api list-object-versions --bucket crearack-backups-lock --prefix postgres/
#   /opt/backups/s3api.sh s3api get-object --bucket crearack-backups-lock --key <clave> --version-id <id> <fichero>
# (en un servidor nuevo, s3api.sh y la config de rclone hay que recrearlos: ver server-management §Object Storage)

# Descomprimir
LATEST=$(ls -t /opt/backups/postgres/*.sql.gz | head -1)
gunzip -k ${LATEST}
SQL_FILE="${LATEST%.gz}"

# Restaurar en PostgreSQL
# Primero, borrar la BD creada por el deploy y recrearla limpia
docker exec crearack-pro-zcmvsl-db-1 psql -U crearack_user -d postgres -c "DROP DATABASE IF EXISTS crearack_pro;"
docker exec crearack-pro-zcmvsl-db-1 psql -U crearack_user -d postgres -c "CREATE DATABASE crearack_pro OWNER crearack_user;"

# Restaurar dump
cat ${SQL_FILE} | docker exec -i crearack-pro-zcmvsl-db-1 psql -U crearack_user crearack_pro

# Verificar
docker exec crearack-pro-zcmvsl-db-1 psql -U crearack_user crearack_pro -c "SELECT count(*) FROM core_organization;"

# Aplicar migraciones pendientes (si las hay)
docker exec crearack-pro-zcmvsl-web-1 python manage.py migrate --noinput

# Reiniciar web para limpiar caches
docker restart crearack-pro-zcmvsl-web-1

Recuperación granular con WAL/PITR

Si el pg_dump es demasiado antiguo y se necesita recuperación más precisa, usar Point-in-Time Recovery con los archivos WAL:

# Los base backups físicos están en Object Storage bajo el prefijo basebackup/
# (corregido el 24-09-2026: la guía decía base_backups/, prefijo que nunca existió)
rclone ls hetzner:crearack-backups-lock/basebackup/

# Los archivos WAL archivados están bajo el prefijo wal/ (antes la guía decía wal_archives/)
rclone ls hetzner:crearack-backups-lock/wal/

# Proceso PITR:
# 1. Descargar el base backup más reciente anterior al punto de recuperación
# 2. Restaurar en el directorio de datos de PostgreSQL
# 3. Crear recovery.conf (o postgresql.conf en PG12+) con restore_command y recovery_target_time
# 4. Iniciar PostgreSQL — aplicará los WAL automáticamente hasta el punto especificado

Los WAL se sincronizan cada 15 minutos al Object Storage (wal_sync.sh). La pérdida máxima de datos con PITR es ~15 minutos. Con pg_dump es hasta 24 horas (cron nocturno). Procedimiento completo: [[crearack-tech—guides—database-admin-guide]] (la antigua Documentation/guides/DATABASE_ADMIN_GUIDE.md del repo fue archivada en abril 2026).

Configurar rclone (para futuros backups)

mkdir -p /root/.config/rclone
cat > /root/.config/rclone/rclone.conf << 'EOF'
[hetzner]
type = s3
provider = Other
access_key_id = <TU_ACCESS_KEY>
secret_access_key = <TU_SECRET_KEY>
endpoint = nbg1.your-objectstorage.com
region = nbg1
acl = private
EOF

Paso 5 — Firewall (2 min)

# Crear script de restauración
cat > /root/restore-firewall.sh << 'SCRIPT'
#!/bin/bash
set -e
for i in $(seq 1 30); do
    if iptables -L DOCKER-USER -n &>/dev/null; then break; fi
    sleep 2
done
iptables -F DOCKER-USER
iptables -A DOCKER-USER -s 127.0.0.0/8 -p tcp --dport 8000 -j ACCEPT
iptables -A DOCKER-USER -s 172.16.0.0/12 -p tcp --dport 8000 -j ACCEPT
iptables -A DOCKER-USER -p tcp --dport 8000 -j DROP
iptables -A DOCKER-USER -s 93.176.0.0/16 -p tcp --dport 3000 -j ACCEPT
# GitHub webhook IPs para auto-deploy de Dokploy (puerto 3000)
iptables -I DOCKER-USER -s 192.30.252.0/22 -p tcp --dport 3000 -j ACCEPT
iptables -I DOCKER-USER -s 185.199.108.0/22 -p tcp --dport 3000 -j ACCEPT
iptables -I DOCKER-USER -s 140.82.112.0/20 -p tcp --dport 3000 -j ACCEPT
iptables -I DOCKER-USER -s 143.55.64.0/20 -p tcp --dport 3000 -j ACCEPT
iptables -A DOCKER-USER -p tcp --dport 3000 -j DROP
iptables -A DOCKER-USER -j RETURN
echo "[$(date)] Firewall rules restored"
SCRIPT
chmod +x /root/restore-firewall.sh

# Crear systemd service
cat > /etc/systemd/system/restore-firewall.service << 'UNIT'
[Unit]
Description=Restore CreaRack iptables DOCKER-USER rules
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
ExecStart=/root/restore-firewall.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
UNIT

systemctl daemon-reload
systemctl enable restore-firewall.service
/root/restore-firewall.sh

Paso 6 — Backup cron (2 min)

# Crear script de backup
mkdir -p /opt/backups/postgres
cat > /opt/backups/pg_backup.sh << 'SCRIPT'
#!/bin/bash
BACKUP_DIR=/opt/backups/postgres
CONTAINER=crearack-pro-zcmvsl-db-1
DATE=$(date +%Y-%m-%d_%H%M)
BACKUP_FILE=${BACKUP_DIR}/crearack_pro_${DATE}.sql.gz
BUCKET=hetzner:crearack-backups/postgres/

docker exec ${CONTAINER} pg_dump -U crearack_user crearack_pro | gzip > ${BACKUP_FILE}

if [ $? -ne 0 ] || [ ! -s "${BACKUP_FILE}" ]; then
    echo "[$(date)] BACKUP FAILED"
    exit 1
fi
echo "[$(date)] Local backup: ${BACKUP_FILE} ($(du -h ${BACKUP_FILE} | cut -f1))"

rclone copy ${BACKUP_FILE} ${BUCKET} --quiet
if [ $? -eq 0 ]; then
    echo "[$(date)] Offsite sync OK"
else
    echo "[$(date)] OFFSITE SYNC FAILED"
fi

find ${BACKUP_DIR} -name '*.sql.gz' -mtime +14 -delete
rclone delete ${BUCKET} --min-age 30d --quiet 2>/dev/null
echo "[$(date)] Cleanup done (local 14d, remote 30d)"
SCRIPT
chmod +x /opt/backups/pg_backup.sh

# Programar cron
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/backups/pg_backup.sh >> /opt/backups/pg_backup.log 2>&1") | crontab -

# Verificar
crontab -l

Paso 7 — DNS (5 min)

  1. Cloudflare Dashboard → DNS → crearack.com
  2. Editar registro A → nueva IP del servidor
  3. Verificar: dig crearack.com → debe mostrar la nueva IP
  4. Esperar propagación DNS (TTL, normalmente 5-30 min con Cloudflare)

Paso 8 — Verificación final

# 1. Contenedores corriendo
docker ps --format 'table {{.Names}}\t{{.Status}}'

# 2. Health check
curl -s https://crearack.com/health
# Esperado: {"status": "ok", ...}

# 3. SSL válido
curl -sI https://crearack.com | head -5
# Esperado: HTTP/2 200, sin errores SSL

# 4. Admin accesible
curl -s -o /dev/null -w "%{http_code}" https://crearack.com/admin/
# Esperado: 200 o 302 (redirect a login)

# 5. API docs
curl -s -o /dev/null -w "%{http_code}" https://crearack.com/api/docs
# Esperado: 200

# 6. Firewall verificado
iptables -L DOCKER-USER -n -v

# 7. UptimeRobot
# Verificar que el monitor vuelve a verde

Checklist resumen


Datos de referencia rápida

DatoValor actual
IP servidor116.203.31.166
OSUbuntu 24.04.4 LTS
Docker29.2.1
Dokployv0.28.8
Traefikv3.6.7
PostgreSQL18-alpine
DB size~20 MB
Media size~654 MB
Backup offsitehetzner:crearack-backups/postgres/ (nbg1)
Backup local/opt/backups/postgres/ (14 días)
Backup remoto30 días retención
Contenedores10 (6 app + 4 Dokploy)
Volúmenes8 persistentes

Qué NO está cubierto por este procedimiento

DatoSituaciónMitigación futura
Media files (stencils, signage uploads)Solo en Docker volume local — no hay backup offsiteAñadir rclone sync de /app/media
VictoriaMetrics (métricas 180 días)Solo en Docker volume localRepoblable desde dispositivos, baja prioridad
Dokploy config (projects, env vars)En la BD interna de DokployExportar secrets a archivo cifrado
Valkey dataAOF en Docker volumeCache reconstruible, no crítico

Recuperación de Staging

El servidor de staging (178.104.131.173, CX23) sigue el mismo procedimiento con estas diferencias:

ParámetroProducciónStaging
Tipo servidor HetznerCCX (4 vCPU, 16 GB)CX23 (1 vCPU, 4 GB)
SECURE_COOKIEStruefalse (HTTP sin SSL)
DNScrearack.comIP directa o subdominio staging
WAL archivingSíNo
Backups offsiteSíNo

El staging no tiene pg_dump ni WAL configurados. La BD se restaura manualmente desde un backup de producción si es necesario.


Generado por: Claude (Anthropic) + Edu Fecha: 07-04-2026

Véase también

Subir