---
title: "Рэзервовае капіраванне, аднаўленне на пэўны момант і праверка аднаўлення"
description: "Стварайце рэзервовыя копіі Quire, аднаўляйце яго на пэўны момант і правярайце працэс практыкаваннем па аднаўленні."
image: "https://docs.quirelms.com/og.png"
---

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

# Рэзервовае капіраванне, аднаўленне на пэўны момант і праверка аднаўлення

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

Архітэктура апісана ў раздзеле 8 `docs/architecture/23-ops.md`. Гэтая інструкцыя прызначана для прадукту Docker Compose. Яна напісана так, каб ёю мог карыстацца чалавек, які яе не пісаў; калі нейкі крок незразумелы, гэта недахоп дакумента.

## Што абаронена і якім чынам <!--quire:what-is-protected-and-how-->

| Аб'ект | Як | Дзе |
| --- | --- | --- |
| База даных | WAL бесперапынна архівуецца, з інтэрвалам не больш за 60 секунд, пачынаючы з першага запуску | том `pgwal` |
| База даных | Базавыя копіі праз `pg_basebackup`, звычайна штодня (`backup-scheduler`) | том `pgbackup` |
| База даных | Зашыфраваныя копіі базавых копій і WAL кожныя пяць хвілін (`backup-offsite`) | асобнае сховішча, якое вы задаяце |
| Файлы | Том `files`. Скапіруйце яго інструментам рэзервовага капіравання хоста або выкарыстоўвайце аб'ектнае сховішча з версіямі | том `files` |
| Сакрэты | `docker/.env`, асабліва `QUIRE_MASTER_KEY` (і `QUIRE_MASTER_KEY_RETIRED`, які яшчэ выкарыстоўваецца), `QUIRE_BACKUP_ENCRYPTION_KEY` і `docker/secrets/audit-signing-key.pem` | Захоўвайце копію па-за гэтым хостам |
| Пошукавыя індэксы, кэшы, вытворныя файлы | Не капіруюцца; ствараюцца нанова | |

Мэты: кропка аднаўлення не далей чым за 60 секунд да збою і аднаўленне на працягу 60 хвілін для базы даных памерам 500 GB.

Часта здараюцца дзве памылкі. Аднаўленне базы даных **без файлаў** прыводзіць да зламаных старонак. Аднаўленне базы даных **без `QUIRE_MASTER_KEY`** не дазваляе расшыфраваць захаваныя ў ёй уліковыя даныя SSO, webhook і інтэграцый; пакуль ратацыя галоўнага ключа не завершыцца без нявырашаных праблем ([key-rotation.md](/be/ops/key-rotation/)), гэта датычыцца і старых ключоў. Абодва кампаненты павінны быць у рэзервовай копіі.

## Стварэнне рэзервовых копій <!--quire:taking-backups-->

Стварыце базавую копію ўсяго кластара:

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

Сістэма пакідае найноўшыя базавыя копіі ў колькасці `QUIRE_BACKUP_KEEP` (першапачаткова 5) і выдаляе WAL, які больш не патрэбны для найстарэйшай копіі, каб архіў не рос бясконца. Заплануйце запуск штодня праз cron або systemd timer на хосце:

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

Або даручыце гэта стэку: профіль `backup` запускае `backup-scheduler`, які стварае базавую копію кожныя `QUIRE_BACKUP_INTERVAL_HOURS` (першапачаткова 24), і `backup-offsite`, апісаны далей.

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

## Зашыфраваныя копіі па-за хостам <!--quire:encrypted-off-host-copies-->

Абодва тамы знаходзяцца на тым жа хосце, што і база даных, а копія на машыне, якая выйшла са строю, не з'яўляецца рэзервовай. `backup-offsite` перадае кожную базавую копію і кожны архіваваны сегмент WAL у асобнае сховішча праз порт сховішча, у зашыфраваным выглядзе, і захоўвае іх там паводле палітыкі захавання:

- **Шыфраванне.** AES-256-GCM з `QUIRE_BACKUP_ENCRYPTION_KEY` (або файлам, зададзеным у `QUIRE_BACKUP_ENCRYPTION_KEY_FILE`): 32 байты, з `openssl rand -hex 32`. Кожны файл мае ўласны nonce і тэга аўтэнтыфікацыі, таму копію нельга прачытаць без ключа, а любая змена будзе выяўлена. Захоўвайце ключ разам з `QUIRE_MASTER_KEY`, але па-за гэтым хостам і асобна ад сховішча копій. Без ключа аднаўленне немагчыма.
- **Месца.** `QUIRE_BACKUP_STORAGE_DRIVER` — `s3`, `azure` або `local` (падключаны аддалены дыск у `QUIRE_BACKUP_STORAGE_ROOT`). Параметры такія ж, як для сховішча файлаў, але з прэфіксам `QUIRE_BACKUP_`: `QUIRE_BACKUP_S3_ENDPOINT`, `QUIRE_BACKUP_S3_BUCKET`, `QUIRE_BACKUP_S3_ACCESS_KEY_ID` і гэтак далей. Выкарыстоўвайце іншы bucket і, па магчымасці, іншы ўліковы запіс, чым для файлаў; уліковыя даныя павінны дазваляць запіс, але не выдаленне, калі правайдар гэта падтрымлівае.
- **Захаванне.** Найноўшыя базавыя копіі ў колькасці `QUIRE_BACKUP_OFFSITE_KEEP` (першапачаткова значэнне `QUIRE_BACKUP_KEEP`, а калі яно не зададзена — 7) і патрэбны для іх WAL; старыя наборы і сегменты выдаляюцца са сховішча.
- **Частата.** Кожныя `QUIRE_BACKUP_SHIP_INTERVAL_SECONDS` секунд (першапачаткова 300). Перадача ідэмпатэнтная: ужо захаванае прапускаецца, а базавая копія лічыцца перададзенай толькі пасля запісу яе маніфеста — апошнім.

Тыя ж каманды можна выканаць уручную:

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

Каб аднавіць сістэму на новым хосце, спачатку вярніце набор копій, а затым выканайце крокі ніжэй, выкарыстоўваючы атрыманую папку замест тома `pgbackup`, а `wal-archive` замест `pgwal`:

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

## Аднаўленне на пэўны момант часу <!--quire:restoring-to-a-point-in-time-->

Выкарыстоўвайце гэтую працэдуру пасля страты даных: няўдалага імпарту, выдаленага курса або міграцыі кантракта, якую трэба адмяніць. Яна замяняе рабочую базу даных, таму спачатку адрэпетуйце працэс з дапамогай практыкавання ніжэй.

1. **Выберыце час**, у UTC, непасрэдна перад пашкоджаннем: `2026-09-24 09:30:00+00`. Момант звычайна можна знайсці ў журнале аўдыту (`/admin/audit`).
2. **Спыніце ўсе сэрвісы, якія запісваюць даныя**: `docker compose -f docker/compose.yaml stop web content worker scheduler collab`
3. **Захавайце пашкоджаны кластар**, пакуль не праверыце аднаўленне:
   ```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. **Распакуйце найноўшую базавую копію, старэйшую за мэтавы час,** у том даных і ўключыце аднаўленне да зададзенага моманту:
   ```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. **Выканайце аднаўленне**: запусціце Postgres адзін раз з наладамі аднаўлення праз перавызначэнне Compose, не змяняючы звычайны файл:
   ```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]
   ```
   Перавызначэнне замяняе ўсю каманду, таму паўтарыце два параметры, ад якіх залежыць аднаўленне: `max_connections` не павінна быць меншай, чым на асноўным серверы (інакш аднаўленне спыніцца з памылкай "insufficient parameter settings"), і падключаны файл `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. **Праверце вынік**, перш чым пускаць карыстальнікаў: ланцуг аўдыту (`docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts`) і наяўнасць страчаных даных.
7. **Вярніцеся да звычайнага рэжыму**: `docker compose -f docker/compose.yaml up -d`. Гэта запускае Postgres зноў з уключаным архіваваннем, пачынаецца новая шкала WAL. Адразу стварыце новую базавую копію.

Назва праекта `quire` дадаецца да назвы кожнага тома; дакладныя назвы пакажа `docker volume ls`.

## Запланаванае практыкаванне праверкі <!--quire:the-scheduled-verification-drill-->

`backup-offsite` таксама запускае практыкаванне кожныя `QUIRE_BACKUP_DRILL_INTERVAL_HOURS` гадзін (першапачаткова 168, штотыдзень), а пасля няўдачы паўтарае яго падчас наступнага запуску. Яно атрымлівае найноўшую базавую копію з-за межаў хоста і ўсе сегменты WAL пасля яе, расшыфроўвае кожны (так правяраецца, што ключ па-ранейшаму працуе і даныя не змяніліся), параўноўвае кожны файл з маніфестам, правярае, што архіў з'яўляецца каталогам даных Postgres, і ўпэўніваецца, што ў WAL пасля копіі няма прабелаў. Справаздача запісваецца ў сховішча як `reports/drill-<time>.json` і ў журнал сэрвісу; няўдалае практыкаванне ўказвае файл або першы адсутны сегмент.

## Практыкаванне аднаўлення <!--quire:the-restore-drill-->

Рэзервовая копія, якую ніколі не аднаўлялі, не з'яўляецца праверанай копіяй. Практыкаванне аднаўляе найноўшую поўную базавую копію, створаную да мэтавага часу, разам з архівам WAL у асобны часовы кластар Postgres, які не мае нічога агульнага з рабочым, і правярае вынік:

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

Мэтавы час задаецца ў UTC менавіта ў такім фармаце. Патрэбна базавая копія, старэйшая за яго, і заархіваваны WAL пасля яго: на новай усталёўцы стварыце базавую копію і дачакайцеся наступнага архіўнага сегмента (пры запісах — не больш за хвіліну), перш чым выбіраць час пасля копіі. Для практыкавання на хосце патрэбныя толькі Docker і bash.

Кожная з наступных праверак можа спыніць практыкаванне:

1. **Магчымасць аднаўлення**: часовы кластар прайгравае даныя да мэтавага часу і запускаецца.
2. **Паўната**: колькасць радкоў у кожнай табліцы параўноўваецца з рабочай базай (`tooling/restore-drill`). Рабочая база змянілася пасля мэтавага часу, таму дапушчальная розніца ў кожны бок — большае з 500 радкоў і дзесятай часткі яе памеру (запісы прыводзяць да адставання, выдаленні — да большай колькасці радкоў у адноўленай базе); партыцыя, створаная пасля мэтавага часу, не лічыцца страчанай табліцай. На больш актыўнай усталёўцы павялічце дапушчальную розніцу праз `QUIRE_DRILL_MAX_BEHIND` і `QUIRE_DRILL_MAX_DRIFT_RATIO`. Адсутная або пустая табліца прыводзіць да памылкі.
3. **Цэласнасць**: хэш-ланцуг аўдыту правяраецца ў адноўленай копіі.
4. **Прыдатнасць**: роля прыкладання можа чытаць даныя з улікам бяспекі на ўзроўні радкоў.
5. **Час**: час ад пачатку да паспяховага выніку параўноўваецца з `QUIRE_DRILL_RTO_SECONDS` (першапачаткова 3600).

Практыкаванне ніколі не запісвае ў рабочую базу або яе тамы: тамы рэзервовых копій і WAL падключаюцца толькі для чытання, а часовы кластар выдаляецца ў канцы незалежна ад выніку.

Задайце `QUIRE_DRILL_REPORT` шлях, каб захаваць справаздачу JSON незалежна ад выніку, і запускайце практыкаванне па раскладзе з хоста 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
```

Запускайце яго штомесяц і перад кожным абнаўленнем. Няўдалае практыкаванне блакуе абнаўленне. Раз на квартал даручайце рэальнае аднаўленне на пэўны момант на запасным хосце чалавеку, які не пісаў гэтую інструкцыю, выкарыстоўваючы толькі гэты дакумент.

## Файлы <!--quire:files-->

Лакальныя файлы захоўваюцца ў томе `files`. Капіруйце іх разам з базай даных і аднаўляйце абодва разам:

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

Пры выкарыстанні аб'ектнага сховішча ўключыце версіянаванне bucket і захоўвайце неактуальныя версіі 35 дзён; у такім выпадку аднаўленне файлаў на пэўны момант забяспечваецца самім сховішчам.

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