---
title: "Backup, point-in-time recovery ug restore drill"
description: "I-backup ang Quire, i-restore kini sa usa ka takna, ug pamatud-i pinaagi sa restore drill."
image: "https://docs.quirelms.com/og.png"
---

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

# Backup, point-in-time recovery ug restore drill

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

Gihulagway ang disenyo sa seksiyon 8 sa `docs/architecture/23-ops.md`. Mao kini ang runbook para sa produkto sa Docker Compose. Gisulat kini aron masunod sa tawo nga wala mosulat niini; depekto sa dokumento kon dili klaro ang usa ka lakang.

## Unsay gipanalipdan ug giunsa <!--quire:what-is-protected-and-how-->

| Asset | Paagi | Asa |
| --- | --- | --- |
| Database | Padayon nga i-archive ang WAL, labing menos matag 60 segundos, sukad sa unang pagsugod | `pgwal` volume |
| Database | Base backup gamit ang `pg_basebackup`, kasagaran kada adlaw (`backup-scheduler`) | `pgbackup` volume |
| Database | Naka-encrypt nga kopya sa base backup ug WAL matag lima ka minuto (`backup-offsite`) | Bulag nga store nga imong ginganlan |
| Files | Ang `files` volume. Kopyaha kini gamit ang backup tool sa host, o gamita ang object storage nga adunay versioning | `files` volume |
| Mga sekreto | `docker/.env`, ilabi na ang `QUIRE_MASTER_KEY` (ug bisan unsang `QUIRE_MASTER_KEY_RETIRED` nga gigamit pa), `QUIRE_BACKUP_ENCRYPTION_KEY`, ug `docker/secrets/audit-signing-key.pem` | Tipigi ang kopya sa gawas niini nga host |
| Search index, cache, rendition | Dili i-backup; tukora pag-usab | |

Target: recovery point nga sulod sa 60 segundos sa kapakyasan, ug restore sulod sa 60 minutos para sa database nga 500 GB.

Dunay duha ka kasagarang sayop. Makapakita og guba nga panid ang database nga gi-restore **nga walay file**. Dili ma-decrypt sa database nga gi-restore **nga walay `QUIRE_MASTER_KEY`** ang SSO, webhook ug integration credential niini; hangtod mahuman ang pagtuyok sa master key nga walay wala masulbad ([key-rotation.md](/ceb/ops/key-rotation/)), apil niini ang mga retired key. Kinahanglan i-backup kining tanan.

## Paghimo og backup <!--quire:taking-backups-->

Base backup sa tibuok cluster:

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

Tipigan niini ang pinakabag-ong `QUIRE_BACKUP_KEEP` ka base backup (default 5) ug papason ang WAL nga dili na gikinahanglan sa labing karaan niini, busa dili motubo hangtod walay kinutoban ang archive. Eskedyulahi kada adlaw gamit ang cron o systemd timer sa host:

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

O ipaiiskedyul kini sa stack pinaagi sa `backup` profile: magpadagan kini sa `backup-scheduler`, nga maghimo og base backup matag `QUIRE_BACKUP_INTERVAL_HOURS` (default 24), ug sa `backup-offsite` nga gihulagway sa sunod.

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

## Naka-encrypt nga kopya sa gawas sa host <!--quire:encrypted-off-host-copies-->

Ania sa samang host sa database ang duha ka volume, ug dili backup ang kopya anaa sa mismong makinang napakyas. Kopyahon sa `backup-offsite` ang matag base backup ug matag gi-archive nga WAL segment ngadto sa bulag nga store pinaagi sa storage port, i-encrypt kini, ug tipigan didto sumala sa retention:

- **Encryption.** AES-256-GCM gamit ang `QUIRE_BACKUP_ENCRYPTION_KEY` (o ang file nga ginganlan sa `QUIRE_BACKUP_ENCRYPTION_KEY_FILE`): 32 bytes, gikan sa `openssl rand -hex 32`. Adunay kaugalingong nonce ug authentication tag ang matag file, busa dili mabasa ang kopya kon walay yawe ug mamatikdan ang kausaban niini. Tipigi ang yawe uban sa `QUIRE_MASTER_KEY`, palayo sa host ug backup store. Dili mahimo ang restore kon walay yawe.
- **Asa tipigan.** Ang `QUIRE_BACKUP_STORAGE_DRIVER` mahimong `s3`, `azure` o `local` (gitaod nga remote disk sa `QUIRE_BACKUP_STORAGE_ROOT`). Parehas kini sa mga setting sa file storage apan gisugdan sa `QUIRE_BACKUP_`: `QUIRE_BACKUP_S3_ENDPOINT`, `QUIRE_BACKUP_S3_BUCKET`, `QUIRE_BACKUP_S3_ACCESS_KEY_ID` ug uban pa. Gamita ang bucket nga lahi sa para sa file ug, kon mahimo, lahi nga account; gamita ang credential nga makasulat apan dili makapapas kon itugot sa provider.
- **Retention.** Tipigan ang pinakabag-ong `QUIRE_BACKUP_OFFSITE_KEEP` ka base backup (default nga `QUIRE_BACKUP_KEEP`, kon wala 7) ug WAL nga gikinahanglan sa labing karaan niini; papason sa store ang mas karaang set ug segment.
- **Kanus-a.** Kada `QUIRE_BACKUP_SHIP_INTERVAL_SECONDS` (default 300). Idempotent ang pagpadala: laktawan ang anaa na sa store, ug maisip nga natipig lang ang base backup kon mahuman na ang manifest niini ug kini ang kataposang isulat.

Mano-mano usab nga modagan ang samang command:

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

Aron i-restore sa bag-ong host, kuhaa una ang set, unya sundon ang mga lakang sa ubos ug gamiton ang directory nga nakuha puli sa `pgbackup` volume ug ang `wal-archive` nga nakuha puli sa `pgwal`:

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

## Pag-restore sa takna <!--quire:restoring-to-a-point-in-time-->

Gamita kini human mawala ang datos: sayop nga import, natangtang nga kurso, o contract migration nga kinahanglan bawi-on. Pulihan niini ang live nga database, busa suwayi una kini pinaagi sa drill sa ubos.

1. **Pilia ang takna nga adtoan**, sa UTC, sa dili pa ang kadaot: `2026-09-24 09:30:00+00`. Kasagaran ipakita sa audit log (`/admin/audit`) ang takna.
2. **Hunonga ang tanang nagsulat**:
   `docker compose -f docker/compose.yaml stop web content worker scheduler collab`
3. **Tipigi ang nadaot nga cluster** hangtod mapamatud-an ang restore:
   ```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. **Ablihi ang pinakabag-ong base backup nga nauna sa target** ngadto sa data volume, ug hangyoa ang targeted recovery:
   ```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. **Bawi-a ang datos**: sugdi makausa ang Postgres gamit ang recovery setting, pinaagi sa Compose override aron dili mausab ang naandan nga file:
   ```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]
   ```
   Pulihan sa override ang tibuok command, busa gisubli niini ang duha ka setting nga gisaligan sa recovery: `max_connections` nga dili moubos sa primary (kay mohunong ang recovery nga adunay “insufficient parameter settings” kon ubos niini) ug ang naka-mount nga `pg_hba.conf`.
   ```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. **Susiha kini** sa dili pa pasudlon ang bisan kinsa: ang audit chain (`docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts`), ug pamatud-i nga mibalik ang nawalang datos.
7. **Balik sa naandan**: `docker compose -f docker/compose.yaml up -d`. I-restart niini ang Postgres nga naka-on ang archiving, ug magsugod ang bag-ong WAL timeline. Paghimo dayon og bag-ong base backup.

Idugang ang `quire` sa sinugdanan sa ngalan sa matag volume; ipakita sa `docker volume ls` ang eksaktong ngalan.

## Nakaiskedyul nga verification drill <!--quire:the-scheduled-verification-drill-->

Magpadagan usab ang `backup-offsite` og drill matag `QUIRE_BACKUP_DRILL_INTERVAL_HOURS` (default 168, kada semana), ug usab sa sunod nga higayon human mapakyas ang usa. Kuhaon niini ang pinakabag-ong base backup gikan sa gawas sa host ug matag WAL segment pagkahuman niini, i-decrypt ang matag usa (pamatud-an niini nga maablihan gihapon sa yawe ug walay nabag-o), itandi ang matag file sa manifest niini, susihon nga Postgres data directory ang archive, ug pamatud-an nga walay putol ang WAL gikan sa backup padayon. Isulat ang report sa store isip `reports/drill-<time>.json` ug sa log sa serbisyo; nganlan sa napakyas nga drill ang file o unang nawalang segment.

## Restore drill <!--quire:the-restore-drill-->

Dili backup ang backup nga wala pa ma-restore. I-restore sa drill ang pinakabag-ong kompleto nga base backup nga gihimo sa wala pa ang target, uban sa WAL archive, ngadto sa scratch Postgres nga walay gipaambit sa live database, ug pamatud-an ang resulta:

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

Kinahanglan eksakto kana nga porma ang UTC target. Kinahanglan adunay base backup nga nauna niini ug gi-archive nga WAL nga miabot lapas niini: sa bag-ong install, paghimo og base backup ug hulata ang sunod nga segment sa archive (kutob usa ka minuto kon adunay pagsulat) sa dili pa mopili og target pagkahuman sa backup. Docker ug bash ra sa host ang gikinahanglan sa drill; wala nay lain.

Mapakyas ang drill sa matag lakang:

1. **Mahimong ma-recover**: mabalik sa scratch cluster ang datos hangtod sa target ug maablihan kini.
2. **Pagkahingpit**: itandi ang gidaghanon sa row sa matag table sa live database (`tooling/restore-drill`). Nakauswag na ang live database sukad sa target, busa mahimong magkalahi ang table hangtod sa mas dako sa 500 ka row o ikapulo sa gidak-on niini, sa bisan hain nga direksiyon (maulahi kini tungod sa mga write; mahimong mas daghan ang na-restore tungod sa mga deletion); dili mawala ang partition nga gibuhat human sa target. Dugangi ang gitugot nga kalainan sa mas busy nga instalasyon gamit ang `QUIRE_DRILL_MAX_BEHIND` ug `QUIRE_DRILL_MAX_DRIFT_RATIO`. Mapakyas kini kon nawala o nahaw-angan ang usa ka table.
3. **Kahusto**: maverify ang audit hash chain sa gi-restore nga kopya.
4. **Magamit**: makabasa ang application role ubos sa row-level security.
5. **Oras**: sugod hangtod malampuson, itandi sa `QUIRE_DRILL_RTO_SECONDS` (default 3600).

Dili gayod kini mosulat sa live database o sa mga volume niini: read only ang pagkakabit sa backup ug WAL volume, ug tangtangon ang scratch cluster sa kataposan, molampos man o mapakyas.

Itakda ang `QUIRE_DRILL_REPORT` sa usa ka path aron isulat didto ang JSON report, molampos man o mapakyas, ug padagana kini sa iskedyul gikan sa Docker host:

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

Padagana kini kada bulan ug sa dili pa ang matag upgrade. Makababag sa upgrade ang napakyas nga drill. Kada quarter, papadagana ang tinuod nga point-in-time restore sa laing tawo nga wala mosulat niining runbook, sa host nga ekstra, ug kini nga dokumento ra ang gamiton niya.

## Mga file <!--quire:files-->

Anaa sa `files` volume ang lokal nga file. I-backup kini kauban sa database ug i-restore silang duha sa samang higayon:

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

Kon object storage ang gamiton, i-on ang bucket versioning ug tipigi sulod sa 35 ka adlaw ang mga daang bersiyon; mahimong paagi sa point-in-time recovery sa file ang bucket mismo.

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