---
title: "Custodia, recuperatio in tempus et exercitium restitutionis"
description: "Custodi Quire, restitue id ad tempus, et id exercitio restitutionis proba."
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/la/llms.txt
> Use this file to discover all available pages before exploring further.

# Custodia, recuperatio in tempus et exercitium restitutionis

<span id="backup-point-in-time-recovery-and-the-restore-drill"></span>

Consilium est `docs/architecture/23-ops.md` sectio 8. Hic est liber operum
pro producti Docker Compose. Scriptus est ut ab eo sequatur qui eum non scripsit;
si aliquis gradus obscurus est, id vitium in hoc documentum est.

## Quid tueatur, et quomodo <!--quire:what-is-protected-and-how-->

| Res | Quomodo | Ubi |
| --- | --- | --- |
| Bases datae | WAL continue archivata, omni 60 secunda saltem, ex prima incursione | volumen `pgwal` |
| Bases datae | Custodiae base cum `pg_basebackup`, cotidie per pristinum (`backup-scheduler`) | volumen `pgbackup` |
| Bases datae | Copiae encryptatae custodiarum base et WAL, omni quinque minuto (`backup-offsite`) | Receptor separatus quem tu nominas |
| Filetuli | Volumen `files`. Eum cum instrumento custodiae hospitis tui copia, aut repositionem obiectorum versionibus instructam utere | volumen `files` |
| Arcana | `docker/.env`, omnibus praecipue `QUIRE_MASTER_KEY` (et quodlibet `QUIRE_MASTER_KEY_RETIRED` adhuc in usu), `QUIRE_BACKUP_ENCRYPTION_KEY`, et `docker/secrets/audit-signing-key.pem` | Copiam extra hunc hostem serva |
| Indices quaestionis, thesauri, renditiones | Non custodiuntur; reficiuntur | |

Metae: punctum recuperationis intra 60 secundas ruinae, et restitutio intra 60
minuta pro basibus datae 500 GB.

Duo errorus communis sunt. Bases datae **sine suis filetulis** restitutae paginas
fractas reddit. Bases datae **sine `QUIRE_MASTER_KEY`** restitutae arcana SSO,
retextoris et integrationum quae tenet dechiffrare non possunt; usque ad id cum
rota clavis magistralis absoluta est nihilque inresolverum
([key-rotation.md](/la/ops/key-rotation/)), haec claves retiras includit. Utraque
partes custodiae sunt.

## Custodias capere <!--quire:taking-backups-->

Custodia base totius agminis:

```sh
docker compose -f docker/compose.yaml --profile backup run --rm backup
```

Ea novissimas `QUIRE_BACKUP_KEEP` custodias base servat (pristinum 5) et WAL quam
vetustissima non iam desiderat putat, ita ut archivum sine fine crescere non
possit. Eam cotidie cum cron aut timer systemd in hospite constitue:

```cron
15 2 * * * cd /srv/quire && docker compose -f docker/compose.yaml --profile backup run --rm backup >> /var/log/quire-backup.log 2>&1
```

Aut sine strue eam constituere sine: profilum `backup` currit `backup-scheduler`,
qui custodiam base omni `QUIRE_BACKUP_INTERVAL_HOURS` (pristinum 24) accipit,
et `backup-offsite`, qui proxime describitur.

```sh
docker compose -f docker/compose.yaml --profile backup up -d
```

## Copiae extra hospitum encryptatae <!--quire:encrypted-off-host-copies-->

Utraque volumina in eodem hospite cum basibus datae vivunt, et custodia in machina
quae ruit non est custodia. `backup-offsite` quamque custodiam base et omne
segmentum WAL archivatum per portum repositionis in receptorem separatum copiat,
encryptatum, et eos ibi sub retentione servat:

- **Encryptio.** AES-256-GCM cum `QUIRE_BACKUP_ENCRYPTION_KEY` (aut filetulo a
  `QUIRE_BACKUP_ENCRYPTION_KEY_FILE` nominato): 32 byta, ex
  `openssl rand -hex 32`. Quisque filetulus suum nonce et notam authenticationis
  habet, ideo copia sine clave legi nequit et quaelibet eius mutatio deprehenditur.
  Clavem cum `QUIRE_MASTER_KEY` serva, longe ab hoc hospite et longe a receptore
  custodiae. Sine clave nulla restitutio est.
- **Ubi.** `QUIRE_BACKUP_STORAGE_DRIVER` est `s3`, `azure` aut `local` (discus
  remotus adfixus in `QUIRE_BACKUP_STORAGE_ROOT`). Constitutiones eae sunt
  filetulorum repositionis cum praefixo `QUIRE_BACKUP_`: `QUIRE_BACKUP_S3_ENDPOINT`,
  `QUIRE_BACKUP_S3_BUCKET`, `QUIRE_BACKUP_S3_ACCESS_KEY_ID`, et ita porro. Bucket
  diversum et, optime, rationem diversam a filetulis utere, cum credentiis quae
  scribere possint non delere si praebitor permittit.
- **Retentio.** Novissimae `QUIRE_BACKUP_OFFSITE_KEEP` custodiae base (pristinum
  `QUIRE_BACKUP_KEEP`, alioquin 7) et WAL quam vetustissima earum desiderat;
  antiquiores seti et segmenta e receptore delentur.
- **Quando.** Omne `QUIRE_BACKUP_SHIP_INTERVAL_SECONDS` (pristinum 300). Navigatio
  idempotens est: quod iam servatum est omittitur, et custodia base solum semel
  cum suus index scriptus est, postremo, ut servata numeratur.

Eadem mandata manu curritur:

```sh
docker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts ship
docker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts verify
```

Ut in novo hospite restituas, primum setum reduce, deinde gradus infra sequere
cum directory petito vice voluminis `pgbackup` et `wal-archive` petito vice
`pgwal`:

```sh
bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore
```

## Restituere ad tempus <!--quire:restoring-to-a-point-in-time-->

Hoc post amissionem datarum utere: mala importatio, cursus deletus, migratio
contractus quam solvere opus est. Vivas bases datae repraesentat, ideo eam
primum cum exercitio infra exerce.

1. **Elige tempus metae**, in UTC, paulo ante damnum:
   `2026-09-24 09:30:00+00`. Liber custodiae (`/admin/audit`) plerumque
   momentum ostendit.
2. **Omne quod scribit compesce**:
   `docker compose -f docker/compose.yaml stop web content worker scheduler collab`
3. **Agrum fractum serva** usque ad id cum restitutio probata est:
   ```sh
   docker compose -f docker/compose.yaml stop postgres
   docker run --rm -v quire_postgres18-data:/from -v quire_postgres-damaged:/to alpine cp -a /from/. /to/
   ```
4. **Novissimam custodiam base veterem quam tempus metae** in volumen datae
   dispone, et recuperationem destinatam posce:
   ```sh
   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'
   ```
5. **Recupera**: Postgres semel cum constitutionibus recuperationis incipe, ex
   superpositione Compose ita ut filetulum normale intactum maneat:
   ```yaml
   # docker/compose.recover.yaml
   services:
     postgres:
       command: [postgres, -c, "restore_command=cp /var/lib/postgresql/wal-archive/%f %p",
                 -c, "recovery_target_time=2026-09-24 09:30:00+00",
                 -c, recovery_target_action=promote, -c, archive_mode=off,
                 -c, max_connections=200, -c, hba_file=/etc/postgresql/pg_hba.conf]
   ```
   Superpositio totum mandatum repraesentat, ideo ea duo constitutiones repetit
   quibus recuperatio pendet: `max_connections` non minus quam
   primarii (alioquin recuperatio cum "insufficient parameter settings" frangitur)
   et `pg_hba.conf` adfixum.
   ```sh
   docker compose -f docker/compose.yaml -f docker/compose.recover.yaml up -d postgres
   docker compose -f docker/compose.yaml logs -f postgres   # wait for "database system is ready"
   ```
6. **Inspece eam** antequam quemquam intromittas: catenam custodiae
   (`docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts`),
   et quod data amissa redierint.
7. **Ad normam redi**: `docker compose -f docker/compose.yaml up -d`. Hic Postgres
   cum archivatione aperta iterum incipit, et novum tempus WAL incipit. Statim
   custodiam base novam cape.

Nomen projectus `quire` praefixum cuique volumini est; `docker volume ls` exacta
nomina monstrat.

## Exercitium explorationis constitutum <!--quire:the-scheduled-verification-drill-->

`backup-offsite` etiam exercitium omni `QUIRE_BACKUP_DRILL_INTERVAL_HOURS`
(pristinum 168, hebdomadale) currit, et rursus in proxima currendo post unum
fractum. Novissimam custodiam base extra hospitum et omne segmentum WAL post eam
petit, quodque decryptat (quod probat clavem adhuc eos aperire et nihil mutatum
esse), quodque filetulum cum suo indice comparat, inspicit archivum esse
directory datae Postgres, et inspicit WAL a custodia in posterum nullum hiatus
habere. Commentarium in receptorem ut `reports/drill-<time>.json` et in librum
servitii scribitur; exercitium fractum filetulum aut primum segmentum deesse
nominat.

## Exercitium restitutionis <!--quire:the-restore-drill-->

Custodia quae numquam restituta est non est custodia. Exercitium novissimam
custodiam base completam ante tempus metae captam, plus archivum WAL, in Postgres
ablutorium qui nihil cum vivo communicat restituit, et resultatum probat:

```sh
docker/scripts/restore-drill.sh                                  # to ninety minutes ago
docker/scripts/restore-drill.sh --target "2026-09-24 09:30:00+00"
```

Tempus metae est UTC eo ipso forma. Custodiam base veterem quam id et WAL
archivatum ultra id desiderat: in nova institutione, custodiam base cape et
expecta proximum segmentum archivatum (cum scripturis saltem minutum) antequam
tempus metae post custodiam eligas. Exercitium Docker et bash in hospite
desiderat, nihil reliqui.

Quisque gradus exercitium frangit:

1. **Restitutibilitas**: agmen ablutorium ad tempus metae reicit et aperitur.
2. **Completudo**: numerus ordinum cuiusque tabulae contra vivas bases datae
   (`tooling/restore-drill`). Bases datae vivae post tempus metae processerunt,
   ideo tabula differre potest eo maiore quod inter 500 ordines et decimam
   partem magnitudinis eius est, utraque via (scripturae eam retardant, deletiones
   restitutio plura tenet); partitio post tempus metae creata non est tabula
   amissa. Latitudinem concessionis in institutione occupatiore cum
   `QUIRE_DRILL_MAX_BEHIND` et `QUIRE_DRILL_MAX_DRIFT_RATIO` fac. Tabula deesse
   aut evacuata frangit.
3. **Integritas**: catena hausti custodiae in copia restituta probatur.
4. **Utilitas**: rola applicationis per securitatem linea row legit.
5. **Tempus**: ab initio ad viride, contra `QUIRE_DRILL_RTO_SECONDS`
   (pristinum 3600).

Numquam in vivas bases datae aut eorum volumina scribit: volumina custodiae et
WAL solum legenti adfiguntur et agmen ablutorium in fine removetur, sive probatum
sive fractum.

`QUIRE_DRILL_REPORT` in viam pone ut commentarium JSON scribatur, sive probatum
sive fractum, et id in ordine ex hospite Docker curra:

```cron
30 3 1 * * cd /srv/quire && QUIRE_DRILL_REPORT=/var/log/quire-drill.json docker/scripts/restore-drill.sh >> /var/log/quire-drill.log 2>&1
```

Id monthly et ante quamque promotionem curra. Exercitium fractum promotionem
prohibet. Semel per quadrimester, fac ut quis qui hunc librum non scripsit
veram restitutionem in tempus in hospite vacuo perficiat, hoc solo documento
usus.

## Filetuli <!--quire:files-->

Filetuli locales in volumine `files` vivunt. Eos cum basibus datae custodi, eodem
tempore, et utrumque una restitue:

```sh
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 .
```

Cum repositio obiectorum, versionem bucket incipe et 35 dierum versionum non
currentium serva; recuperatio in tempus pro filetulis tum ipsius bucket est.

Source: https://docs.quirelms.com/la/ops/backup-restore/index.mdx
