Un agente anterior a 1.1.0 no reporta su install_path, así que el panel caía al default de plataforma y ACTUALIZAR abortaba cuando la instalación vivía en otra carpeta (p. ej. C:\Aduanasoft\CloudRestoreAS-win). Era un huevo-y-gallina: la ruta se empieza a reportar en 1.1.x, que es justo lo que no se podía instalar. Se agrega la captura manual de la ruta por servidor. No hace falta esquema nuevo ni lógica de resolución nueva: el upsert del estado ya usa install_path = COALESCE(EXCLUDED.install_path, actual), así que el valor capturado sobrevive los reportes sin ruta del agente viejo, y resolveInstallPath y cras-verify ya leen esa misma columna. Cuando el servidor quede en 1.1.x su propio reporte lo sustituye por la ruta real. De paso, dos fallos de configuración que costaron el diagnóstico: - GITEA_TOKEN con los `<>` de la plantilla se veía como un 401 opaco de Gitea, idéntico al de un token revocado. Se valida la forma antes de llamar, el aviso sale al cargar la pantalla y 401 y 403 dejan de colapsar al mismo texto. Un rechazo ahora deja línea en los logs: no dejaba ninguna. - PANEL_PUBLIC_URL sin el puerto apuntaba a otro servicio. Esa URL se siembra en el config/.env del destino también al ACTUALIZAR, así que rompería un agente que ya reportaba: se avisa y se aborta antes de tocar el servidor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
112 lines
5.9 KiB
Plaintext
112 lines
5.9 KiB
Plaintext
# Credenciales SQL Server (mismo usuario en todos los nodos salvo sql_password en database_nodes).
|
||
# Si no defines PANEL_MSSQL_*, se usan DB_PRIMARY_* / DB_SECONDARY_* como respaldo.
|
||
PANEL_MSSQL_USER=sa
|
||
PANEL_MSSQL_PASSWORD=Clave.2025
|
||
# En contenedor Docker: reescribe localhost en server_name → host.docker.internal
|
||
# PANEL_MSSQL_DOCKER=true
|
||
# Depuración de bases duplicadas: tolerancia de tamaño (fracción 0–1) para marcar una base como
|
||
# segura para borrar del servidor viejo. El nuevo debe pesar >= (1 - tolerancia) del viejo. Default 0.2.
|
||
# PANEL_DEDUP_SIZE_TOLERANCE=0.2
|
||
# "Mandar al nuevo": carpeta donde el SQL viejo escribe el .bak (default: data_folder del servidor).
|
||
# PANEL_DEDUP_BACKUP_FOLDER=
|
||
# Ventana de verificación tras enviar (ms) antes de dar la base por "en tránsito". Default 180000.
|
||
# PANEL_DEDUP_MOVE_VERIFY_TIMEOUT_MS=180000
|
||
# Intervalo de sondeo de la verificación (ms). Default 5000.
|
||
# PANEL_DEDUP_MOVE_POLL_MS=5000
|
||
# requestTimeout de SQL Server para BACKUP/DROP (el default de node-mssql, 15 s, no alcanza para
|
||
# bases reales). Default 3600000 (1 h).
|
||
# PANEL_DEDUP_DDL_TIMEOUT_MS=3600000
|
||
|
||
# PostgreSQL - Usuarios del panel + catálogo ControlDesk (tablas a24c.* las crea otra app)
|
||
DB_POSTGRES_HOST=localhost
|
||
DB_POSTGRES_PORT=5434
|
||
DB_POSTGRES_USER=postgres
|
||
DB_POSTGRES_PASS=Control.
|
||
DB_POSTGRES_DB=CONTROLDESK
|
||
|
||
# JWT Secret (cambiar en producción)
|
||
JWT_SECRET=change-this-secret-in-production-please-use-a-long-random-string
|
||
|
||
# Ruta de respaldos (LEGACY / fallback): carpeta única leída por la vista "Respaldos
|
||
# Almacenados" y por /backup?file=... cuando no se especifica restaurador. Las vistas nuevas
|
||
# "Respaldos Restaurados" y "Restores Fallidos" resuelven la carpeta de CADA restaurador de
|
||
# forma relativa (derivada de la Entrada que reporta cada uno), sin usar esta variable.
|
||
# Apúntala a una carpeta de procesados accesible por filesystem (local o share) si usas el modo legacy.
|
||
BACKUP_PATH=D:/BackupSFTP/
|
||
|
||
# SMTP para envío de avisos de alertas críticas
|
||
# Si SMTP_HOST está vacío los botones "Enviar avisos" no hacen nada (sin error).
|
||
SMTP_HOST=
|
||
SMTP_PORT=587
|
||
SMTP_USER=
|
||
SMTP_PASSWORD=
|
||
SMTP_FROM=
|
||
SMTP_USE_TLS=true
|
||
|
||
# Integración CloudRestoreAS
|
||
# Token Bearer que CloudRestoreAS envía en Authorization: Bearer <token>
|
||
# para /api/restore/target-for, /api/restore/job-result y /api/restore/instance-config.
|
||
# DEBE ser idéntico al valor "Token API del PANEL" en CloudRestoreAS (pestaña Config).
|
||
# Generar uno largo y aleatorio, p. ej.:
|
||
# node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||
CLOUDRESTORE_API_TOKEN=
|
||
|
||
# Clave compartida con a24c para cifrar la contraseña SQL de los nodos en reposo.
|
||
# El panel cifra en Fernet (AES-128-CBC + HMAC) derivando la clave como sha256(SECRET_KEY),
|
||
# EXACTAMENTE igual que a24c, para que a24c pueda descifrar database_nodes.sql_password.
|
||
# ⚠️ DEBE ser idéntica a la SECRET_KEY del backend de a24c, o a24c no podrá conectar.
|
||
SECRET_KEY=
|
||
|
||
# [LEGADO] Clave AES-256 (32 bytes) del formato antiguo `gcm:` del panel. Solo se usa para
|
||
# LEER credenciales cifradas antes de migrar a Fernet; las nuevas se escriben con SECRET_KEY.
|
||
# Puede quedar vacía en instalaciones nuevas. Generar (si aplica) con:
|
||
# node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
|
||
ENCRYPTION_KEY=
|
||
|
||
# ============================================================================
|
||
# Distribución de versiones de CloudRestoreAS (pantalla /versiones-cras)
|
||
#
|
||
# Los binarios se publican en el registro de paquetes GENÉRICOS de Gitea desde el build
|
||
# local del repo CloudRecoveryAS (`build-all.sh --publish`). El panel los descubre leyendo
|
||
# esa API, los descarga verificando el sha256 que Gitea calcula, y los instala en cada
|
||
# servidor de restauración por SSH/SFTP.
|
||
# ============================================================================
|
||
|
||
# Instancia de Gitea y organización dueña del paquete.
|
||
GITEA_BASE_URL=https://git.aduanasoft.com
|
||
GITEA_OWNER=ADUANASOFT
|
||
CRAS_PACKAGE_NAME=cloudrestoreas
|
||
|
||
# PAT de Gitea. El panel solo LEE el registro, así que basta el scope `read:package`.
|
||
# (El token con `write:package` vive en la máquina de build, no aquí.)
|
||
# Sin este token /versiones-cras carga pero avisa que no puede sincronizar.
|
||
#
|
||
# El valor va DESNUDO: sin los `<>` de una plantilla, sin comillas y sin espacios. Compose los
|
||
# pasa literales y Gitea responde 401, indistinguible de un token revocado.
|
||
# Y tras cambiarlo hay que RECREAR el contenedor (`docker compose up -d`), no reiniciarlo:
|
||
# `environment:` con `${VAR:-}` congela el valor al crearlo y `restart` no relee este archivo.
|
||
GITEA_TOKEN=
|
||
|
||
# Caché local de artefactos. Cada uno pesa ~270 MB y se publican dos por versión, así que la
|
||
# carpeta crece ~540 MB por versión; CRAS_CACHE_KEEP_VERSIONS limita cuántas se conservan
|
||
# (las versiones activas nunca se borran).
|
||
CRAS_RELEASES_DIR=./local-cras-releases
|
||
CRAS_CACHE_KEEP_VERSIONS=3
|
||
|
||
# Origen del bind-mount de esa caché en el HOST (docker-compose.prod.yml). Es una ruta del host,
|
||
# no del contenedor, así que debe existir EN EL SISTEMA DEL HOST: en un host Windows
|
||
# `C:/Aduanasoft/cras-releases`, en uno Linux `/srv/panel/cras-releases`. Una ruta estilo POSIX
|
||
# en un host Windows no falla: Docker la crea dentro de su propia VM, donde nadie la ve ni la
|
||
# respalda y consume el disco virtual.
|
||
CRAS_RELEASES_HOST_PATH=
|
||
|
||
# URL con la que el agente instalado reportará al panel. El instalador remoto la siembra en el
|
||
# config/.env del servidor destino, así que TIENE que ser alcanzable desde esos servidores (no
|
||
# localhost). Si se omite se usa ORIGIN.
|
||
#
|
||
# DEBE incluir el puerto si el panel no está detrás de un proxy en 443. El panel escucha en 3000,
|
||
# y en cpanel-a24 el 443 lo sirve el PHP legado: sin el `:3000` el agente le pediría todo a otro
|
||
# servicio y recibiría 404. Se siembra también al ACTUALIZAR, así que una URL mal puesta rompe
|
||
# un agente que ya funcionaba. Lo más seguro es dejarla vacía y que tome ORIGIN.
|
||
PANEL_PUBLIC_URL=
|