---
title: "Copi wrth gefn, adfer i adeg benodol a phrawf adfer"
description: "Gwneud copi wrth gefn o Quire, ei adfer i adeg benodol, a phrofi hynny gyda'r ymarfer adfer."
image: "https://docs.quirelms.com/og.png"
---

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

# Copi wrth gefn, adfer i adeg benodol a phrawf adfer

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

Mae'r dyluniad yn adran 8 o `docs/architecture/23-ops.md`. Dyma'r llawlyfr
ar gyfer cynnyrch Docker Compose. Fe'i hysgrifennwyd i gael ei ddilyn gan rywun na
wnaeth ei ysgrifennu; os nad yw cam yn glir, mae hynny'n ddiffyg yn y ddogfen hon.

## Beth sy'n cael ei ddiogelu, a sut <!--quire:what-is-protected-and-how-->

| Ased | Sut | Ble |
| --- | --- | --- |
| Y gronfa ddata | WAL yn cael ei archifo'n barhaus, o leiaf bob 60 eiliad, o'r cychwyn cyntaf | Cyfrol `pgwal` |
| Y gronfa ddata | Copïau wrth gefn sylfaenol gyda `pg_basebackup`, bob dydd yn ddiofyn (`backup-scheduler`) | Cyfrol `pgbackup` |
| Y gronfa ddata | Copïau wedi'u hamgryptio o'r copïau wrth gefn sylfaenol a'r WAL, bob pum munud (`backup-offsite`) | Storfa ar wahân a enwir gennych |
| Ffeiliau | Y gyfrol `files`. Copïwch hi gydag offeryn copi wrth gefn eich host, neu defnyddiwch storfa wrthrychau â fersiynau | Cyfrol `files` |
| Cyfrinachau | `docker/.env`, yn enwedig `QUIRE_MASTER_KEY` (ac unrhyw `QUIRE_MASTER_KEY_RETIRED` sy'n dal i gael ei ddefnyddio), `QUIRE_BACKUP_ENCRYPTION_KEY` a `docker/secrets/audit-signing-key.pem` | Cadwch gopi oddi ar y host hwn |
| Mynegeion chwilio, caches, rendradau | Heb eu gwneud wrth gefn; cânt eu hailadeiladu | |

Nodau: pwynt adfer o fewn 60 eiliad i'r methiant, ac adferiad
o fewn 60 munud ar gyfer cronfa ddata 500 GB.

Mae dau gamgymeriad yn gyffredin. Mae cronfa ddata a adferir **heb ei ffeiliau** yn dangos
tudalennau toredig. Ni all cronfa ddata a adferir **heb `QUIRE_MASTER_KEY`**
ddadgryptio'r manylion mewngofnodi SSO, webhook ac integreiddio sydd ynddi; hyd nes bydd newid
yr allwedd feistr wedi'i gwblhau heb ddim heb ei ddatrys ([key-rotation.md](/cy/ops/key-rotation/)),
mae hynny'n cynnwys yr allweddi sydd wedi ymddeol. Mae'r ddau'n rhan o'r copi wrth gefn.

## Gwneud copïau wrth gefn <!--quire:taking-backups-->

Copi wrth gefn sylfaenol o'r clwstwr cyfan:

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

Mae'n cadw'r copïau wrth gefn sylfaenol diweddaraf hyd at `QUIRE_BACKUP_KEEP` (diofyn 5) ac yn tocio
WAL nad oes ei angen ar yr un hynaf mwyach, felly ni all yr archif dyfu'n ddiderfyn.
Trefnwch ef bob dydd gyda cron neu amserydd systemd ar y 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
```

Neu gadewch i'r stack ei drefnu: mae proffil `backup` yn rhedeg `backup-scheduler`,
sy'n gwneud copi wrth gefn sylfaenol bob `QUIRE_BACKUP_INTERVAL_HOURS` (diofyn 24),
a `backup-offsite`, a ddisgrifir nesaf.

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

## Copïau wedi'u hamgryptio oddi ar y host <!--quire:encrypted-off-host-copies-->

Mae'r ddwy gyfrol ar yr un host â'r gronfa ddata, ac nid copi wrth gefn yw un ar y
peiriant a fethodd. Mae `backup-offsite` yn copïo pob copi wrth gefn sylfaenol
a phob segment WAL sydd wedi'i archifo i storfa ar wahân drwy'r porth storio,
yn eu hamgryptio, a'u cadw yno yn ôl cyfnod cadw:

- **Amgryptio.** AES-256-GCM gydag `QUIRE_BACKUP_ENCRYPTION_KEY` (neu'r ffeil
  a enwir gan `QUIRE_BACKUP_ENCRYPTION_KEY_FILE`): 32 beit, wedi'i chynhyrchu drwy
  `openssl rand -hex 32`. Mae gan bob ffeil ei nonce ei hun a thag dilysu,
  felly ni ellir darllen copi heb yr allwedd a chaiff unrhyw newid iddo ei
  ganfod. Cadwch yr allwedd gydag `QUIRE_MASTER_KEY`, oddi wrth y host hwn ac oddi wrth y
  storfa copi wrth gefn. Heb yr allwedd ni ellir adfer.
- **Ble.** Mae `QUIRE_BACKUP_STORAGE_DRIVER` yn `s3`, `azure` neu `local` (disg
  bell wedi'i mowntio yn `QUIRE_BACKUP_STORAGE_ROOT`). Gosodiadau storio ffeil yw'r rhain gyda rhagddodiad
  `QUIRE_BACKUP_`: `QUIRE_BACKUP_S3_ENDPOINT`, `QUIRE_BACKUP_S3_BUCKET`,
  `QUIRE_BACKUP_S3_ACCESS_KEY_ID`, ac ati. Defnyddiwch fwced gwahanol ac, yn ddelfrydol,
  gyfrif gwahanol i'r ffeiliau, gyda manylion mewngofnodi sy'n gallu ysgrifennu ond nid dileu os yw'r darparwr yn caniatáu hynny.
- **Cadw.** Copïau wrth gefn sylfaenol diweddaraf `QUIRE_BACKUP_OFFSITE_KEEP` (diofyn
  `QUIRE_BACKUP_KEEP`, fel arall 7) a'r WAL sydd ei angen ar yr hynaf ohonynt; caiff hen
  setiau a segmentau eu dileu o'r storfa.
- **Pryd.** Bob `QUIRE_BACKUP_SHIP_INTERVAL_SECONDS` (diofyn 300). Mae cludo
  yn idempotent: hepgorir yr hyn sydd eisoes wedi'i storio, a dim ond ar ôl ysgrifennu ei faniffest, yn olaf, y cyfrifir copi wrth gefn sylfaenol fel un wedi'i storio.

Mae'r un gorchymyn yn rhedeg â llaw:

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

I adfer ar host newydd, dewch â set yn ôl yn gyntaf, yna dilynwch y camau isod
gyda'r cyfeiriadur a gafwyd yn lle cyfrol `pgbackup` a'r
`wal-archive` a gafwyd yn lle `pgwal`:

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

## Adfer i adeg benodol <!--quire:restoring-to-a-point-in-time-->

Defnyddiwch hwn ar ôl colli data: mewnforio gwael, cwrs wedi'i ddileu, mudo
contractio y mae angen ei ddadwneud. Mae'n disodli'r gronfa ddata fyw, felly ymarferwch
ag ef drwy'r prawf isod yn gyntaf.

1. **Dewiswch yr amser targed**, yn UTC, ychydig cyn y difrod:
   `2026-09-24 09:30:00+00`. Mae'r cofnod archwilio (`/admin/audit`) fel arfer yn dangos y
   foment.
2. **Stopiwch bopeth sy'n ysgrifennu**:
   `docker compose -f docker/compose.yaml stop web content worker scheduler collab`
3. **Cadwch y clwstwr sydd wedi'i ddifrodi** nes bod yr adferiad wedi'i ddilysu:
   ```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. **Dadbecynnu'r copi wrth gefn sylfaenol diweddaraf sy'n hŷn na'r targed** i'r gyfrol
   ddata, a gofyn am adfer wedi'i dargedu:
   ```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. **Adfer**: cychwynnwch Postgres unwaith gyda gosodiadau adfer, drwy
   wrthwneud Compose fel na newidir y ffeil arferol:
   ```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]
   ```
   Mae'r gwrthwneud yn disodli'r gorchymyn cyfan, felly mae'n ailadrodd y ddau osodiad
   y mae adfer yn dibynnu arnynt: `max_connections` heb fod yn is na'r prif un
   (fel arall daw adfer i ben â “insufficient parameter settings”) a'r
   `pg_hba.conf` a fowntiwyd.
   ```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. **Gwiriwch ef** cyn gadael neb i mewn: y gadwyn archwilio
   (`docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts`),
   a bod y data coll wedi dychwelyd.
7. **Dychwelwch i'r arfer**: `docker compose -f docker/compose.yaml up -d`. Mae hyn yn
   ailgychwyn Postgres gydag archifo ymlaen, a bydd llinell amser WAL newydd yn dechrau. Gwnewch
   gopi wrth gefn sylfaenol newydd yn syth.

Mae enw'r prosiect `quire` yn rhagddodi pob cyfrol; mae `docker volume ls` yn dangos yr
union enwau.

## Y prawf dilysu wedi'i drefnu <!--quire:the-scheduled-verification-drill-->

Mae `backup-offsite` hefyd yn rhedeg prawf bob `QUIRE_BACKUP_DRILL_INTERVAL_HOURS`
(diofyn 168, wythnosol), ac eto ar y rhediad nesaf ar ôl methiant. Mae'n nôl y copi wrth gefn sylfaenol diweddaraf oddi ar y host a phob segment WAL wedyn, yn dadgryptio pob un (sy'n profi bod yr allwedd yn dal i'w hagor ac na newidiwyd dim), yn cymharu pob
ffeil â'i maniffest, yn gwirio bod yr archif yn gyfeiriadur data Postgres, ac yn
sicrhau nad oes bwlch yn y WAL o'r copi wrth gefn ymlaen. Ysgrifennir yr adroddiad yn
 y storfa fel `reports/drill-<time>.json` ac yng nghofnod y gwasanaeth; mae prawf a fethodd yn enwi'r ffeil neu'r segment coll cyntaf.

## Y prawf adfer <!--quire:the-restore-drill-->

Nid copi wrth gefn yw un nas adferwyd erioed. Mae'r prawf yn adfer y copi wrth gefn sylfaenol cyflawn diweddaraf a wnaed cyn y targed, ynghyd â'r archif WAL,
i Postgres dros dro nad yw'n rhannu dim â'r un byw, ac yn profi'r
canlyniad:

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

Mae'r targed yn UTC yn union yn y ffurf honno. Mae angen copi wrth gefn sylfaenol sy'n hŷn nag ef
ac WAL wedi'i archifo ar ei ôl: mewn gosodiad newydd, gwnewch gopi wrth gefn sylfaenol ac arhoswch am y segment archif nesaf (uchafswm munud gyda rhywfaint o ysgrifennu) cyn dewis targed ar ôl y copi wrth gefn. Mae angen Docker a bash ar y host ar y prawf, dim byd
arall.

Mae pob cam yn methu'r prawf:

1. **Posibilrwydd adfer**: mae'r clwstwr dros dro'n ailchwarae hyd at y targed ac yn agor.
2. **Cyflawnrwydd**: cyfrif rhesi pob tabl yn erbyn y gronfa fyw
   (`tooling/restore-drill`). Mae'r gronfa fyw wedi symud ymlaen ers y targed,
   felly gall tabl amrywio gan y mwyaf o 500 rhes neu ddegfed o'i faint, i'r ddau gyfeiriad (mae ysgrifennu'n peri ei fod ar ei hôl hi, mae dileu'n peri bod mwy yn yr adferiad);
   nid yw rhaniad a grëwyd ar ôl y targed yn dabl coll. Ehangwch y
   lwfans ar osodiad prysurach gyda `QUIRE_DRILL_MAX_BEHIND` a
   `QUIRE_DRILL_MAX_DRIFT_RATIO`. Mae tabl coll neu wag yn achosi methiant.
3. **Uniondeb**: dilysir cadwyn hash yr archwiliad ar y copi a adferwyd.
4. **Defnyddioldeb**: mae rôl y rhaglen yn darllen drwy ddiogelwch ar lefel rhes.
5. **Amser**: o'r dechrau i'r golau gwyrdd, yn erbyn `QUIRE_DRILL_RTO_SECONDS`
   (diofyn 3600).

Nid yw byth yn ysgrifennu i'r gronfa ddata fyw na'i chyfeintiau: mae cyfrolau copi wrth gefn a WAL
wedi'u mowntio'n ddarllen-yn-unig, ac mae'r clwstwr dros dro'n cael ei dynnu ar y diwedd,
boed yn llwyddo neu'n methu.

Gosodwch `QUIRE_DRILL_REPORT` i lwybr i ysgrifennu adroddiad JSON, p'un a yw'n pasio neu'n
methu, a'i redeg ar amserlen o'r host Docker:

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

Rhedwch ef bob mis a chyn pob uwchraddiad. Mae prawf a fethodd yn rhwystro'r uwchraddiad.
Unwaith bob chwarter, gofynnwch i rywun na ysgrifennodd y llawlyfr hwn wneud adferiad
pwynt-amser go iawn ar host sbâr, gan ddefnyddio'r ddogfen hon yn unig.

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

Mae ffeiliau lleol yn byw yn y gyfrol `files`. Gwnewch gopi wrth gefn ohoni gyda'r gronfa ddata, ar yr
un pryd, ac adferwch y ddau gyda'i gilydd:

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

Gyda storfa wrthrychau, trowch fersiynu bwced ymlaen a chadwch 35 diwrnod o
fersiynau nad ydynt yn gyfredol; adferiad pwynt-amser ar gyfer ffeiliau yw'r bwced ei hun wedyn.

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