---
title: "Нөөцлөлт, цагийн цэгийн сэргээлт болон сэргээлтийн дасгал"
description: "Quire-г нөөцлөх, цагийн цэгт сэргээх, мөн сэргээлтийн дасгалгаар баталгаажуулах."
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/mn/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>

Зохион байгуулалт нь `docs/architecture/23-ops.md` хэсэг 8 юм. Энэ нь Docker Compose бүтээгдэхүүний бүртгэл-логик юм. Үүнийг бичээгүй хүн дагаж биелүүлэхээр бичигдсэн; хэрэв алхам тодорхой биш бол энэ нь энэ баримт бичгийн дутагдал юм.

## Юу хамгаалагддаг, хэрхэн <!--quire:what-is-protected-and-how-->

| Хөрөнгө | Хэрхэн | Хаана |
| --- | --- | --- |
| Өгөгдлийн сан | WAL архивлагдаж байна, хамгийн ихдээ 60 секунд тутам, анхны ачааллагаанаас хойш | `pgwal` volume |
| Өгөгдлийн сан | `pg_basebackup`-тай үндсэн нөөцлөлт, өгөгдсөнөөр өдөртөө (`backup-scheduler`) | `pgbackup` volume |
| Өгөгдлийн сан | Үндсэн нөөцлөлт болон WAL-ийн шифрэлсэн хуулбарууд, таван минут тутам (`backup-offsite`) | Та нэрлэдэг тусгай хадгалалт |
| Файлууд | `files` volume. Хостынхаа нөөцлөлтийн хэрэгслээр хуулна уу, эсвэл хувилбартай объект хадгалалт ашиглаарай | `files` volume |
| Нууцлалууд | `docker/.env`, юуны өмнө `QUIRE_MASTER_KEY` (мөн одоо ч ашиглагдаж буй аль ч `QUIRE_MASTER_KEY_RETIRED`), `QUIRE_BACKUP_ENCRYPTION_KEY`, мөн `docker/secrets/audit-signing-key.pem` | Хуулбарыг энэ хостоос гадагш хадгалаарай |
| Хайлтын индексүүд, кэшүүд, хувилбарууд | Нөөцлөөгүй; дахин бүтээгдсэн | |

Зорилтууд: сэргээх цэг нь ослоос хойш 60 секундын дотор, мөн 500 GB өгөгдлийн санд 60 минутын дотор сэргээлт.

Хоёр алдаа нийтлэг байдаг. **Файлуудгүйгээр** сэргээсэн өгөгдлийн сан эвдрэлтэй хуудсуудыг харуулна. **`QUIRE_MASTER_KEY`-гүйгээр** сэргээсэн өгөгдлийн сан SSO, вебхүүк, холболтын итгэмжлэлүүдээ задалж чадахгүй; мастер түлхүүрийн эргэлт шийдвэрлэгдээгүй зүйлгүйгээр дуусах хүртэл ([key-rotation.md](/mn/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-->

Хоёр volume ч мөн өгөгдлийн сантай ижил хост дээр байдаг бөгөөд ассан машины нөөцлөлт нөөцлөлт биш юм. `backup-offsite` нь хадгалалтын портоор дамжуулан бүх үндсэн нөөцлөлт, бүр архивлагдсан WAL сегментийг тусгай хадгалалт руу шифрлээд, хадгалалтын хугацааны дор тэнд барьдаг:

- **Шифрлэлт.** `QUIRE_BACKUP_ENCRYPTION_KEY` (эсвэл `QUIRE_BACKUP_ENCRYPTION_KEY_FILE`-оор нэрлэсэн файл)-тай AES-256-GCM: 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`, гэх мэт. Файлаас өөр сав, хэрэв боломж бол өөр данс ашиглаарай — бичих ч устгаж чадахгүй эрхтэй итгэмжлэлээр.
- **Хадгалалтын хугацаа.** Хамгийн шинэ `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` volume-ын оронд, мөн татсан `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. **Зорилтот цагаас хуучин хамгийн шинэ үндсэн нөөцлөлтийг** өгөгдлийн volume руу тайлаад, чиглүүлсэн сэргээлт хүснэ үү:
   ```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 override-аар:
   ```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]
   ```
   Override нь бүх командыг орлуулдаг тул сэргээлтээс хамаарах хоёр тохиргоог давтан бичнэ: `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` нь volume бүрийн угтвар; `docker volume ls` яг тэр нэрүүдийг харуулна.

## Товлосон баталгаажуулалтын дасгал <!--quire:the-scheduled-verification-drill-->

`backup-offsite` мөн `QUIRE_BACKUP_DRILL_INTERVAL_HOURS` (өгөгдсөнөөр 168, долоо хоног тутам) тутам дасгал ажиллуулдаг бөгөөд нэг нь амжилтгүй болсны дараагийн удаад дахин ажиллуулна. Тэр хамгийн шинэ хостын гаднах үндсэн нөөцлөлт, түүний дараах бүр WAL сегментийг татаж авч, бүрнийг нь задална (энэ нь түлхүүр одоо ч тэдгээрийг нээж, юуг ч өөрчлөөгүйг нотолно), файл бүрийг манифесттэй нь харьцуулж, архив нь PostgreSQL өгөгдлийн сангийн хавтас мөн үү, мөн нөөцлөлтөөс хойшхи WAL-д завсарлага байхгүйг шалгана. Тайланг хадгалалт руу `reports/drill-<time>.json` байдлаар болон үйлчилгээний лог руу бичнэ; амжилтгүй дасгал файл эсвэл анхны дутуу сегментийг нэрлэнэ.

## Сэргээлтийн дасгал <!--quire:the-restore-drill-->

Хэзээ ч сэргээгдээгүй нөөцлөлт нөөцлөлт биш юм. Дасгал нь зорилтот цагаас өмнө авсан хамгийн шинэ бүрэн үндсэн нөөцлөлт, нэмэлтээр WAL архивийг, амьдтайгаа ямар ч зүйл хуваалцаагүй туршилтын PostgreSQL руу сэргээгээд үр дүнг баталгаажуулдаг:

```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)-тай харьцуулсан.

Энэ нь хэзээ ч амьд өгөгдлийн сан эсвэл түүний volume руу бичдэггүй: нөөцлөлт болон WAL volume-ууд зөвхөн унших эрхээр залгагдсан бөгөөд туршилтын бүлгийг төгсгөлд нь, амжилттай эсэхээс үл хамааран устгадаг.

JSON тайлан бичүүлэхийн тулд `QUIRE_DRILL_REPORT`-ийг замд тогтооно уу, амжилттай эсэхээс үл хамааран, мөн 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` volume-д байрлана. Үүнийг өгөгдлийн сантай хамт, ижил мөчид нөөцлөөд, хоёуланг нь хамтдаа сэргээнэ үү:

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

Объект хадгалалттай бол савны хувилбарчилалтыг нээгээд 35 хоногийн хуучин бус хувилбаруудыг барина уу; файлуудын цагийн цэгийн сэргээлт нь түүнээс хойш савны өөрийнх байна.

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