O deseño descríbese na sección 8 de docs/architecture/23-ops.md. Este é o manual de operacións do produto Docker Compose. Está redactado para que o poida seguir alguén que non o escribiu; se algún paso non queda claro, é un defecto deste documento.
Que se protexe e como
Recurso
Método
Lugar
Base de datos
Arquivo continuo de WAL, como máximo cada 60 segundos, desde o primeiro inicio
Volume pgwal
Base de datos
Copias base con pg_basebackup, unha vez ao día de xeito predeterminado (backup-scheduler)
Volume pgbackup
Base de datos
Copias cifradas das copias base e do WAL cada cinco minutos (backup-offsite)
Almacén independente que indiques
Ficheiros
Volume files. Copia coas ferramentas do host ou utiliza almacenamento de obxectos con versións
Volume files
Segredos
docker/.env, sobre todo QUIRE_MASTER_KEY (e calquera QUIRE_MASTER_KEY_RETIRED que aínda se use), QUIRE_BACKUP_ENCRYPTION_KEY e docker/secrets/audit-signing-key.pem
Garda unha copia fóra deste host
Índices de busca, cachés e versións derivadas
Non se gardan nas copias; recréanse
Obxectivos: perder como máximo os cambios dos últimos 60 segundos e completar a restauración en 60 minutos para unha base de datos de 500 GB.
Dous erros son habituais. Se restauras unha base de datos sen os ficheiros, as páxinas amosaranse danadas. Se a restauras sen QUIRE_MASTER_KEY, non poderás descifrar as credenciais SSO, de webhook e de integración que contén; ata completar unha rotación da clave mestra sen valores sen resolver (key-rotation.md), isto inclúe as claves retiradas. Ambas as cousas forman parte da copia de seguridade.
Facer copias de seguridade
Copia base de todo o clúster:
docker compose -f docker/compose.yaml --profile backup run --rm backup
Conserva as copias base máis recentes indicadas por QUIRE_BACKUP_KEEP (5 de xeito predeterminado) e elimina o WAL que xa non precise a copia máis antiga, para que o arquivo non medre sen límite.
Programa unha copia diaria cun cron ou temporizador systemd no host:
15 2 * * * cd /srv/quire && docker compose -f docker/compose.yaml --profile backup run --rm backup >> /var/log/quire-backup.log 2>&1
Ou deixa que a pila a programe: o perfil backup inicia backup-scheduler, que crea unha copia base cada QUIRE_BACKUP_INTERVAL_HOURS (24 de xeito predeterminado), e tamén o servizo backup-offsite, que se describe a continuación.
docker compose -f docker/compose.yaml --profile backup up -d
Copias cifradas fóra do host
Ambos os volumes están no mesmo host que a base de datos; unha copia na máquina que fallou non serve de nada. backup-offsite copia cada copia base e cada segmento WAL arquivado a un almacén diferente mediante o porto de almacenamento; cifra os datos e aplícalles a política de conservación:
Cifrado. AES-256-GCM mediante QUIRE_BACKUP_ENCRYPTION_KEY (ou o ficheiro indicado por QUIRE_BACKUP_ENCRYPTION_KEY_FILE): 32 bytes, xerados con openssl rand -hex 32. Cada ficheiro ten un nonce propio e unha etiqueta de autenticación, polo que non se pode ler a copia sen a clave e detéctase calquera modificación. Garda a clave xunto con QUIRE_MASTER_KEY, lonxe deste host e do almacén das copias. Sen a clave non se pode restaurar.
Destino.QUIRE_BACKUP_STORAGE_DRIVER é s3, azure ou local (un disco remoto montado en QUIRE_BACKUP_STORAGE_ROOT). Os axustes son os mesmos que para o almacenamento de ficheiros, co prefixo QUIRE_BACKUP_: QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID e demais. Utiliza un bucket distinto e, se é posible, unha conta diferente da dos ficheiros, con credenciais que poidan escribir pero non eliminar, se o provedor o permite.
Conservación. Garda as copias base máis recentes indicadas por QUIRE_BACKUP_OFFSITE_KEEP (o valor de QUIRE_BACKUP_KEEP ou, se non está establecido, 7) e o WAL que precise a máis antiga; as copias e os segmentos anteriores elimínanse do almacén.
Frecuencia. Cada QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (300 segundos de xeito predeterminado). O envío é idempotente: omite o que xa está no almacén e só considera gardada unha copia base cando se escribiu o seu manifesto, como último paso.
Tamén podes executar o mesmo comando manualmente:
docker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts shipdocker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts verify
Para restaurar nun host novo, recupera primeiro un conxunto e, a continuación, segue os pasos máis abaixo utilizando o directorio descargado no lugar do volume pgbackup e o arquivo wal-archive descargado no lugar de pgwal:
bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore
Restaurar a un punto no tempo
Utiliza este procedemento tras unha perda de datos: unha importación incorrecta, un curso eliminado ou unha migración de eliminación que haxa que desfacer. Substitúe a base de datos activa, polo que antes debes ensaiar a operación coa proba máis abaixo.
Escolle a hora de destino, en UTC e xusto antes do dano: 2026-09-24 09:30:00+00. O rexistro de auditoría (/admin/audit) adoita indicar o momento.
Detén todo o que escriba datos: docker compose -f docker/compose.yaml stop web content worker scheduler collab.
Conserva o clúster danado ata verificar a restauración:
docker compose -f docker/compose.yaml stop postgresdocker run --rm -v quire_postgres18-data:/from -v quire_postgres-damaged:/to alpine cp -a /from/. /to/
Extrae no volume de datos a copia base máis recente anterior ao destino e activa a recuperación para o punto seleccionado:
docker run --rm -v quire_pgbackup:/backups:ro -v quire_postgres18-data:/var/lib/postgresql postgres:18-alpine sh -euc ' base="$(ls -1d /backups/base-* | sort | tail -n 1)" # or the one before the target rm -rf /var/lib/postgresql/18/docker && mkdir -p /var/lib/postgresql/18/docker tar -xzf "$base/base.tar.gz" -C /var/lib/postgresql/18/docker touch /var/lib/postgresql/18/docker/recovery.signal chown -R postgres:postgres /var/lib/postgresql/18/docker && chmod 700 /var/lib/postgresql/18/docker'
Recupera: inicia Postgres unha vez cos axustes de recuperación, mediante un ficheiro de substitución de Compose para non modificar o ficheiro habitual:
A substitución reemplaza o comando completo, polo que repite os dous
axustes dos que depende a recuperación: max_connections debe ser polo
menos igual ao da instancia principal (se non, a recuperación detense cun
erro «insufficient parameter settings») e tamén hai que indicar o ficheiro
montado pg_hba.conf.
docker compose -f docker/compose.yaml -f docker/compose.recover.yaml up -d postgresdocker compose -f docker/compose.yaml logs -f postgres # wait for "database system is ready"
Comproba a restauración antes de permitir o acceso: valida a cadea de auditoría (docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts) e confirma que se recuperaron os datos perdidos.
Volve á execución normal: docker compose -f docker/compose.yaml up -d. Postgres reiníciase co arquivo activado e comeza unha nova liña temporal de WAL. Fai inmediatamente unha nova copia base.
O nome de proxecto quire úsase como prefixo de cada volume; docker volume ls amosa os nomes exactos.
Proba de verificación programada
backup-offsite tamén executa unha proba cada QUIRE_BACKUP_DRILL_INTERVAL_HOURS (168 horas, é dicir, cada semana, de xeito predeterminado), e repítea na seguinte execución se unha proba falla. Descarga a copia base externa máis recente e todos os segmentos WAL posteriores, descifra cada ficheiro (o que demostra que a clave segue abríndoos e que non se modificaron), compara cada ficheiro co seu manifesto, comproba que o arquivo é un directorio de datos Postgres e verifica que non haxa ocos no WAL desde a copia base. O informe gárdase no almacén como reports/drill-<time>.json e no rexistro do servizo; se a proba falla, indícase o ficheiro ou o primeiro segmento que falta.
Proba de restauración
Unha copia de seguridade que nunca se restaurou non está probada. A proba restaura a copia base completa máis recente anterior ao obxectivo, xunto co arquivo WAL, nunha instancia Postgres temporal que non comparte nada coa instancia activa, e comproba o resultado:
docker/scripts/restore-drill.sh # to ninety minutes agodocker/scripts/restore-drill.sh --target "2026-09-24 09:30:00+00"
O destino debe estar en UTC e seguir exactamente ese formato. Precisa unha copia base anterior e segmentos WAL posteriores: nunha instalación nova, fai unha copia base e agarda ao seguinte segmento arquivado (como máximo un minuto se hai escrituras) antes de escoller un destino posterior á copia. Para executala só fan falta Docker e bash no host.
A proba falla se falla calquera dos seguintes pasos:
Recuperabilidade: o clúster temporal volve ao destino e ábrese correctamente.
Integridade: compárase o número de filas de cada táboa coa base activa (tooling/restore-drill). Como a base activa avanzou desde o momento de destino, unha táboa pode diferir nunha cantidade igual ao maior destes valores: 500 filas ou unha décima parte do seu tamaño, en calquera dirección (as escrituras reducen o número restaurado e as eliminacións fan que a copia teña máis); unha partición creada despois do destino non se considera unha táboa perdida. Podes ampliar a tolerancia nunha instalación con máis actividade mediante QUIRE_DRILL_MAX_BEHIND e QUIRE_DRILL_MAX_DRIFT_RATIO. A ausencia dunha táboa ou que estea baleira fan fallar a proba.
Integridade: a cadea hash de auditoría verifícase na copia restaurada.
Usabilidade: o rol da aplicación pode ler aplicando a seguridade a nivel de fila.
Tempo: mide o tempo desde o inicio ata o resultado correcto e compárao con QUIRE_DRILL_RTO_SECONDS (3600 de xeito predeterminado).
A proba nunca escribe na base de datos activa nin nos seus volumes: os volumes da copia base e do WAL móntanse en modo de só lectura, e o clúster temporal elimínase ao rematar, tanto se a proba pasa como se falla.
Establece QUIRE_DRILL_REPORT cunha ruta para escribir un informe JSON tanto se a proba pasa como se falla, e prográmaa desde o host Docker:
Execútaa cada mes e antes de cada actualización. Se falla, non actualices. Unha vez por trimestre, pide a alguén que non escribise este manual que faga unha restauración real a un punto no tempo nun host de proba utilizando só este documento.
Ficheiros
Os ficheiros locais están no volume files. Fai a copia ao mesmo tempo que a da base de datos e restáuraas xuntas:
docker run --rm -v quire_files:/files:ro -v "$PWD":/out alpine tar -czf /out/files-$(date -u +%Y%m%d).tar.gz -C /files .
Se utilizas almacenamento de obxectos, activa o versionado do bucket e conserva durante 35 días as versións que deixaron de estar vixentes; a recuperación a un punto no tempo dos ficheiros depende entón do propio bucket.