Saltar al contenido principal

Preparación para la recuperación

Libre WebUI ofrece un inventario de recuperación de solo lectura como primera barrera de seguridad. Informa del estado conocido y de las condiciones que bloquean una instantánea. No adquiere un bloqueo de mantenimiento ni copia, cifra, sube, elimina, repara o restaura datos.

libre-webui recovery-check --json > recovery-inventory.json

Desde el código, ejecuta una vez npm run build:backend y sustituye libre-webui recovery-check por npm run recovery:check --. Las instalaciones npx y Homebrew inspeccionan ~/.libre-webui; DATA_DIR y rutas explícitas lo sustituyen.

El estado de salida es 0 sin bloqueos, 1 con informe completo pero bloqueos y 2 por argumentos inválidos o fallo inesperado. Usa --data-dir PATH o --database PATH. El inventario predeterminado solo acepta DATA_DIR/data.sqlite y rechaza base, WAL o SHM enlazados, simbólicos o no regulares. Una --database explícita puede estar fuera, pero ella y sus acompañantes deben ser archivos regulares no simbólicos. Sin --data-dir, su padre se trata como raíz para inventariar clave, blobs y plugins juntos.

El runtime también lee definiciones históricas desde el directorio plugins del paquete backend y, si PLUGINS_DIR es relativo, su ubicación histórica. Esas rutas bloquean una instantánea solo del volumen si contienen definiciones personalizadas. Los despliegues empaquetados pueden pasar varias veces --legacy-plugins-dir PATH.

En Compose privado, ejecútalo dentro del contenedor:

docker exec libre-webui \
libre-webui recovery-check --json --data-dir /app/backend/data

Qué comprueba el inventario

El informe JSON versionado registra:

  • versiones de aplicación, Node.js, sistema y arquitectura;
  • tamaños de SQLite/WAL/SHM, quick_check, claves foráneas, huella del esquema, versión de usuario, tablas ausentes y validación sin seguir enlaces antes de crear una copia privada;
  • lectura, escritura, número de archivos y bytes del directorio;
  • origen de clave y huella irreversible de 16 caracteres;
  • validación sin enlaces y de vínculo único de .encryption_key;
  • presencia, cantidad, tamaño e inclusión de plugins, blobs cifrados, medios, voces, texto, vectores heredados y de plataforma con ACL;
  • autenticación limitada y de solo lectura de todos los blobs y envolturas vectoriales, con fragmentos, checksums y claves;
  • autenticación de envolturas AES-GCM reconocibles en chats, notas, documentos, preferencias, secretos, galería, correo y voces vinculadas mediante AAD;
  • tareas, ejecuciones y vistas de Work y sus volúmenes Docker, PVC Kubernetes o identidades de rutas; los volúmenes deben llevar etiqueta gestionada e ID exacto;
  • estados de trabajos multimedia y duraderos, intentos, flujos, eventos y cursor global;
  • autenticación de cargas cifradas y validación sintáctica limitada de referencias opacas; y
  • bloqueos, advertencias y datos externos al directorio.

Nunca incluye claves, secretos JWT, credenciales, contenido de plugins o usuarios ni rutas literales del host. Solo emite presencia de secretos y la huella no reversible. Un montaje de solo lectura produce advertencia, no bloqueo, pero nunca inicies la aplicación contra la instantánea de solo lectura.

Bloqueos

Cualquier bloqueo hace fallar la barrera: base ausente o corrupta, esquema incompleto, clave ausente o conflictiva, ciphertext corrupto o no autenticado, límites excedidos, directorio ilegible, SQLite enlazado o irregular, ejecuciones, vistas o trabajos activos, workspace ausente o mal etiquetado, discrepancias o huecos de eventos, plugins externos o un plano de control incapaz de verificar workspaces. Detén la actividad y resuelve dependencias; no edites el informe para ocultarlo.

Las cargas duraderas se autentican contra la identidad y como JSON canónico limitado. Las referencias opacas solo se limitan y validan sintácticamente porque no existe un repositorio autoritativo para probar el destino. El informe marca referenceTargetsVerified false y advierte sin revelar valores.

Los campos heredados preceden al marcador obligatorio: el texto claro genuino sigue siendo legible y no cuenta como ciphertext. Las envolturas canónicas siempre se autentican; valores de tres partes con IV o etiqueta de ancho de envoltura fallan cerrados si están malformados. Las voces tienen una envoltura inequívoca vinculada a perfil, propietario y campo. encryption.legacyCiphertext informa totales sin exponer texto.

Con users.email_lookup de v4, también se autentica cada correo y se recalcula su token separado por dominio. Un token ausente, incorrecto o asociado a correo null bloquea. Las bases anteriores siguen siendo compatibles.

Límite actual de la copia

El asistente privado detiene la aplicación si estaba activa y usa imagen inmutable, volumen y entorno para crear un archivo solo. El manifiesto se firma con Ed25519 y la carga completa se cifra con una clave AES-256-GCM del operador. Incluye SQLite, blobs, vectores, selectores y configuración protegida. Verifica firma, checksum y carga antes de publicar. libre-webui-restore solo acepta un volumen Docker nuevo, verifica el inventario y publica configuración privada en un directorio nuevo.

La configuración protegida incluye pool, conexión, inactividad, sentencias y bloqueo de migración PostgreSQL; conexión Redis; cuotas de blobs; selectores; prefijo S3 y modo de direccionamiento. Está cifrada, no en el manifiesto claro, y se publica con modo 0600.

El archivo solo excluye volúmenes Work, PVC, carpetas del host, modelos Ollama y estado externo. Mantén visibles las exclusiones y respalda Work por separado. El perfil team usa un flujo offline: snapshot PostgreSQL, objetos S3 versionados, inventario PGVector, configuración e identidad de clave en el mismo formato, verificados contra objetivos limpios. Redis se reconstruye desde SQL.

La copia team autentica cada trabajo y evento del snapshot. Su inventario firmado registra trabajos, eventos, flujos, cursor, envolturas, referencias y texto autenticado. Cada flujo debe ser 1..last_sequence y el cursor PostgreSQL no puede retrasarse. La restauración repite y exige coincidencia. Los huecos entre cursores globales son válidos porque la identidad no es transaccional; la secuencia por flujo sí es el contrato contiguo.

Si PLUGINS_DIR está fuera de DATA_DIR, se marca excluido y cualquier definición bloquea hasta respaldar también ese directorio. Lo mismo se aplica a rutas heredadas; JSON simbólico, irregular o ilegible siempre bloquea.

Los trabajos duraderos están activos en ambos perfiles. Se bloquea mientras haya intento o Work activo, se validan cargas y cabezas, y se conserva SQL. Solo usa worker integrado; team usa worker externo y Redis solo para despertar y distribuir.

En producción guarda secretos en un gestor, archivos cifrados fuera del host y prueba restauraciones limpias. El inventario es una comprobación previa, no un bloqueo ni prueba de todos los recursos externos.

Comandos de copia firmada y cifrada

La barrera recovery-check se ejecuta antes de crear la copia. Los ejemplos usan libre-webui global y el subcomando libre-webui backup. Sustitúyelo por npx --yes libre-webui@latest o, desde código, compila y usa npm run recovery:backup --. La imagen expone /usr/local/bin/libre-webui. Team exige pg_dump y pg_restore de PostgreSQL 16, incluidos en imagen y fórmula Homebrew; instálalos explícitamente para npm/npx.

Genera la clave de archivo AES-256-GCM custodiada por el operador y el par de claves de firma Ed25519 en un directorio privado. Después, traslada las claves privadas a un almacenamiento protegido fuera del host:

install -d -m 0700 /absolute/private/libre-backup-keys
libre-webui backup keygen \
--directory /absolute/private/libre-backup-keys

Crea y verifica un archivo solo en reposo:

libre-webui backup create \
--offline \
--data-dir /absolute/path/to/libre-data \
--output /absolute/backups/libre-solo.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-private-key /absolute/private/libre-backup-keys/backup-signing-private.pem

libre-webui backup verify \
--archive /absolute/backups/libre-solo.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

Previsualiza y aplica solo a un destino nuevo vacío:

libre-webui backup restore-preflight \
--archive /absolute/backups/libre-solo.lwbackup \
--target /absolute/restore/libre-data \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

libre-webui backup restore-apply \
--archive /absolute/backups/libre-solo.lwbackup \
--target /absolute/restore/libre-data \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

libre-webui backup restore-verify \
--target /absolute/restore/libre-data

Para team, detén réplicas y workers y conserva cargado PostgreSQL/S3/keyring:

libre-webui backup create-team \
--offline \
--output /absolute/backups/libre-team.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-private-key /absolute/private/libre-backup-keys/backup-signing-private.pem

Carga una base y bucket versionado vacíos. La previsualización prueba que están vacíos; aplicar restaura y verifica PostgreSQL, S3 y PGVector y escribe configuración privada:

libre-webui backup restore-team-preflight \
--archive /absolute/backups/libre-team.lwbackup \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

libre-webui backup restore-team-apply \
--archive /absolute/backups/libre-team.lwbackup \
--configuration-output /absolute/restore/libre-team-config \
--encryption-key /absolute/private/libre-backup-keys/backup-encryption.key \
--signing-public-key /absolute/private/libre-backup-keys/backup-signing-public.pem

Nunca dirijas una restauración a la base de datos de origen, al bucket de origen, a un directorio de datos existente ni a un directorio de configuración que contenga archivos. Conserva la clave pública de firma junto al procedimiento de restauración; poseer solo el archivo y la clave pública no permite descifrar la carga. Si rollback queda incompleto, considera ambos objetivos sucios: limpia PostgreSQL y todas las versiones y marcadores bajo el prefijo S3, y repite restore-team-preflight antes de reintentar.

Simulacros programados y verificados

Una copia nunca restaurada es esperanza, no recuperación. El simulacro ejecuta todo sin caída ni operador:

  1. Prepara una copia en reposo: SQLite mediante API online y archivos físicamente; espera a que no haya trabajos activos.
  2. Crea un archivo firmado y cifrado AES-256-GCM con claves efímeras y el inventario completo.
  3. Verifica, restaura en destino aislado y vuelve a verificar.
  4. Registra duración como RTO y separación entre éxitos como límite de RPO, y elimina todo. No conserva copias ni claves.

Activa RECOVERY_DRILL_INTERVAL_HOURS (por ejemplo 24). Un lease evita duplicados. Sistema muestra historial y «Ejecutar ahora» mediante GET /api/recovery/drills y POST /api/recovery/drills/run. Los fallos desatendidos alertan a cada administrador y webhooks; los manuales informan directamente. RECOVERY_DRILL_HISTORY conserva 60 entradas de forma predeterminada.

Los simulacros cubren solo SQLite. Team conserva backup create-team y su ensayo sigue siendo un paso manual.