---
title: "Backup, point-in-time recovery আৰু restore drill"
description: "Docker Compose-ৰে Quire backup কৰক, সময়লৈ restore কৰক আৰু recovery অভ্যাস কৰক।"
image: "https://docs.quirelms.com/og.png"
---

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

# Backup, point-in-time recovery আৰু restore drill

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

ডিজাইন `docs/architecture/23-ops.md`ৰ section 8-ত। Docker Compose product-ৰ বাবে এই runbook। ইয়াক অনুসৰণ কৰা ব্যক্তিজনে লিখা নাছিল বুলি ধৰি লিখা হৈছে; কোনো step অস্পষ্ট হ’লে এই নথিৰ দোষ।

## কি সুৰক্ষিত, আৰু কেনেকৈ <!--quire:what-is-protected-and-how-->

| Asset | কেনেকৈ | ক’ত |
| --- | --- | --- |
| Database | প্ৰথম boot-ৰ পৰা অবিৰতভাৱে, সৰ্বাধিক প্ৰতি 60 ছেকেণ্ডত WAL archive | `pgwal` volume |
| Database | `pg_basebackup`ৰে base backup, ডিফল্টভাৱে দৈনিক (`backup-scheduler`) | `pgbackup` volume |
| Database | Base backup আৰু WAL-ৰ encrypted copy, প্ৰতি পাঁচ মিনিটত (`backup-offsite`) | আপোনাৰ নাম দিয়া পৃথক store |
| File | `files` volume। Host backup tool-ৰে copy কৰক অথবা version থকা object storage ব্যৱহাৰ কৰক | `files` volume |
| Secret | `docker/.env`, বিশেষকৈ `QUIRE_MASTER_KEY` (আৰু এতিয়াও ব্যৱহৃত `QUIRE_MASTER_KEY_RETIRED`), `QUIRE_BACKUP_ENCRYPTION_KEY`, আৰু `docker/secrets/audit-signing-key.pem` | এই host-ৰ বাহিৰত copy ৰাখক |
| Search index, cache, rendition | Backup নহয়; পুনৰ নিৰ্মাণ কৰা হয় | |

লক্ষ্য: বিফলতাৰ 60 ছেকেণ্ডৰ ভিতৰত recovery point, আৰু 500 GB database-ৰ বাবে 60 মিনিটৰ ভিতৰত restore।

দুটা ভুল সাধাৰণ। **File অবিহনে** restore কৰা database-এ ভঙা page দেখুৱায়। **`QUIRE_MASTER_KEY` অবিহনে** restore কৰা database-এ ইয়াৰ SSO, webhook আৰু integration credential decrypt কৰিব নোৱাৰে; একো unresolved নথকাকৈ master key rotation সম্পূৰ্ণ নোহোৱালৈ ([key-rotation.md](/as/ops/key-rotation/)), ইয়াত retired key-ও অন্তৰ্ভুক্ত। দুয়োটাই backup-ৰ অংশ।

## Backup লওক <!--quire:taking-backups-->

সম্পূৰ্ণ cluster-ৰ base backup:

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

ই আটাইতকৈ নতুন `QUIRE_BACKUP_KEEP`টা base backup ৰাখে (ডিফল্ট 5) আৰু আটাইতকৈ পুৰণিটোৱে আৰু নলগা WAL prune কৰে, যাতে archive সীমাহীনভাৱে নাবাঢ়ে। Host-ত cron বা systemd timer-ৰে দৈনিক schedule কৰক:

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

অথবা stack-ক schedule কৰিবলৈ দিয়ক: `backup` profile-এ `backup-scheduler` চলায়, যিয়ে প্ৰতিটো `QUIRE_BACKUP_INTERVAL_HOURS` ঘণ্টাত base backup লয় (ডিফল্ট 24), আৰু তলত বৰ্ণনা কৰা `backup-offsite`-ও চলে।

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

## Host-ৰ বাহিৰত encrypted copy <!--quire:encrypted-off-host-copies-->

দুয়োটা volume database-ৰ সৈতে একে host-ত থাকে; বিফল হোৱা machine-ত থকা backup backup নহয়। `backup-offsite`-এ প্ৰতিটো base backup আৰু archived WAL segment পৃথক store-লৈ storage port-ৰে encrypted copy কৰে আৰু retention নিয়মত ৰাখে:

- **Encryption.** `QUIRE_BACKUP_ENCRYPTION_KEY` (অথবা `QUIRE_BACKUP_ENCRYPTION_KEY_FILE`-এ নাম দিয়া file)-সহ AES-256-GCM: `openssl rand -hex 32`ৰে সৃষ্টি কৰা 32 byte। প্ৰতিটো file-ৰ নিজা nonce আৰু authentication tag থাকে, সেয়ে key অবিহনে copy পঢ়িব নোৱাৰি আৰু পৰিৱৰ্তন হ’লে ধৰা পৰে। Key-টো `QUIRE_MASTER_KEY`ৰ সৈতে, এই host আৰু backup store-ৰ পৰা আঁতৰত ৰাখক। Key নাথাকিলে restore নহয়।
- **ক’ত.** `QUIRE_BACKUP_STORAGE_DRIVER` হৈছে `s3`, `azure` অথবা `local` (`QUIRE_BACKUP_STORAGE_ROOT`ত mount কৰা remote disk)। Setting-সমূহ file storage-ৰেই `QUIRE_BACKUP_` prefix-সহ: `QUIRE_BACKUP_S3_ENDPOINT`, `QUIRE_BACKUP_S3_BUCKET`, `QUIRE_BACKUP_S3_ACCESS_KEY_ID` আদি। File-ৰ পৰা বেলেগ bucket, ভাল হ’লে বেলেগ account ব্যৱহাৰ কৰি provider-এ অনুমতি দিলে লিখিব পৰা কিন্তু delete কৰিব নোৱাৰা credential দিয়ক।
- **Retention.** আটাইতকৈ নতুন `QUIRE_BACKUP_OFFSITE_KEEP`টা base backup (ডিফল্ট `QUIRE_BACKUP_KEEP`, নহ’লে 7) আৰু আটাইতকৈ পুৰণিটোক লগা WAL; পুৰণি set আৰু segment store-ৰ পৰা delete হয়।
- **কেতিয়া.** প্ৰতিটো `QUIRE_BACKUP_SHIP_INTERVAL_SECONDS` ছেকেণ্ডত (ডিফল্ট 300)। Shipping idempotent: আগতে store হোৱা বস্তু skip হয়; manifest শেষত লিখাৰ পিছতহে base backup store হোৱা বুলি গণ্য হয়।

হাতেৰে একে 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
```

নতুন host-ত restore কৰিবলৈ, আগতে এটা set ঘূৰাই আনি তাৰ পিছত তলৰ step অনুসৰণ কৰক; download কৰা directory-টো `pgbackup` volume-ৰ সলনি আৰু download কৰা `wal-archive`টো `pgwal`ৰ সলনি ব্যৱহাৰ কৰক:

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

## সময়ৰ এটা বিন্দুলৈ restore <!--quire:restoring-to-a-point-in-time-->

Data হেৰালে ব্যৱহাৰ কৰক: ভুল import, মচি পেলোৱা পাঠ্যক্ৰম, অথবা বাতিল কৰিবলগীয়া contract migration। ই live database সলনি কৰে, সেয়ে তলৰ drill-ৰে আগতে অভ্যাস কৰক।

1. **Target time বাছক**, UTC-ত ক্ষতিৰ ঠিক আগৰ সময়: `2026-09-24 09:30:00+00`। Audit log (`/admin/audit`)-এ সাধাৰণতে সেই মুহূৰ্ত দেখুৱায়।
2. **লিখা কৰা সকলো বন্ধ কৰক**: `docker compose -f docker/compose.yaml stop web content worker scheduler collab`
3. **Restore পৰীক্ষা নোহোৱালৈ ক্ষতিগ্ৰস্ত cluster ৰাখক**:
   ```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. **Target-তকৈ পুৰণি আটাইতকৈ নতুন base backup** data volume-ত unpack কৰি 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. **Recover**: স্বাভাৱিক file নসলনি কৰিবলৈ Compose override-ৰ পৰা recovery setting-সহ এবাৰ Postgres আৰম্ভ কৰক:
   ```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-এ সম্পূৰ্ণ command সলনি কৰে, সেয়ে recovery-ৰ প্ৰয়োজনীয় দুটা setting পুনৰ দিয়ে: `max_connections` primary-তকৈ কম নহ’ব (নহ’লে recovery “insufficient parameter settings”ৰে বন্ধ হয়) আৰু mount কৰা `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. **মানুহক সোমাবলৈ দিয়াৰ আগতে পৰীক্ষা কৰক**: audit chain (`docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts`) আৰু হেৰোৱা data ঘূৰি আহিছে নে।
7. **স্বাভাৱিক অৱস্থালৈ ঘূৰক**: `docker compose -f docker/compose.yaml up -d`। ই archiving অন কৰি Postgres পুনৰ আৰম্ভ কৰে আৰু নতুন WAL timeline আৰম্ভ হয়। লগে লগে নতুন base backup লওক।

Project name `quire` প্ৰতিটো volume-ৰ আগত যোগ হয়; `docker volume ls`-এ হুবহু নাম দেখুৱায়।

## Schedule কৰা verification drill <!--quire:the-scheduled-verification-drill-->

`backup-offsite`-এ প্ৰতিটো `QUIRE_BACKUP_DRILL_INTERVAL_HOURS` ঘণ্টাত (ডিফল্ট 168, সাপ্তাহিক) আৰু বিফলতাৰ পিছৰ পৰৱৰ্তী pass-ত drill চলায়। ই host-ৰ বাহিৰৰ নতুনতম base backup আৰু তাৰ পিছৰ প্ৰতিটো WAL segment fetch কৰি decrypt কৰে (key-এ এতিয়াও খুলিব পাৰে আৰু একো সলনি হোৱা নাই প্ৰমাণ হয়), প্ৰতিটো file manifest-ৰ সৈতে তুলনা কৰে, archive Postgres data directory নে পৰীক্ষা কৰে আৰু backup-ৰ পিছৰ WAL-ত gap নাই বুলি নিশ্চিত কৰে। Report-টো `reports/drill-<time>.json` হিচাপে store আৰু service log-ত লিখা হয়; বিফল drill-এ file বা প্ৰথম missing segment-ৰ নাম কয়।

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

কেতিয়াও restore নকৰা backup, backup নহয়। Drill-এ target-ৰ আগতে লোৱা নতুনতম সম্পূৰ্ণ base backup আৰু WAL archive live-ৰ পৰা একো share নকৰা scratch Postgres-ত restore কৰি ফল প্ৰমাণ কৰে:

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

Target হুবহু এই format-ৰ UTC সময়। ইয়াৰ আগৰ এটা base backup আৰু তাৰ পিছৰ archived WAL লাগে: নতুন install-ত base backup লৈ পৰৱৰ্তী archive segment আহিবলৈ (write থাকিলে সৰ্বাধিক এক মিনিট) অপেক্ষা কৰি তাৰ পিছৰ target বাছক। Host-ত Docker আৰু bash-হে লাগে।

প্ৰতিটো step-এ drill fail কৰে:

1. **Recoverability**: scratch cluster-এ target-লৈ replay কৰি খোলে।
2. **Completeness**: live database-ৰ বিপৰীতে প্ৰতিটো table-ৰ row count (`tooling/restore-drill`)। Live database target-ৰ পিছত আগবাঢ়িছে; সেয়ে যিকোনো দিশত table-ৰ পাৰ্থক্য 500 row বা size-ৰ এক-দশমাংশৰ ভিতৰত যিটো ডাঙৰ সেইখিনি হ’ব পাৰে (write-এ restore পিছত ৰাখে, deletion-এ restore-ত বেছি ৰাখে); target-ৰ পিছত সৃষ্টি হোৱা partition হেৰোৱা table নহয়। অধিক ব্যস্ত install-ত `QUIRE_DRILL_MAX_BEHIND` আৰু `QUIRE_DRILL_MAX_DRIFT_RATIO`ৰে allowance বঢ়াওক। Missing বা খালী table-এ fail কৰে।
3. **Integrity**: restored copy-ত audit hash chain verify হয়।
4. **ব্যৱহাৰযোগ্যতা**: application role-এ row-level security-ৰে পঢ়ে।
5. **সময়**: আৰম্ভণিৰ পৰা সফল হোৱালৈ `QUIRE_DRILL_RTO_SECONDS`ৰ বিপৰীতে (ডিফল্ট 3600)।

ই live database বা volume-ত কেতিয়াও লিখা নকৰে: backup আৰু WAL volume read-only mount হয় আৰু pass বা fail যিয়েই হওক শেষত scratch cluster আঁতৰোৱা হয়।

JSON report (pass বা fail) লিখিবলৈ `QUIRE_DRILL_REPORT`ক path দিয়ক আৰু Docker host-ৰ পৰা schedule কৰক:

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

মাহে এবাৰ আৰু প্ৰতিটো upgrade-ৰ আগতে চলাওক। বিফল drill-এ upgrade বন্ধ কৰে। প্ৰতি quarter-ত এই runbook নিলিখা কোনোবাক কেৱল এই নথি ব্যৱহাৰ কৰি spare host-ত প্ৰকৃত point-in-time restore কৰিবলৈ দিয়ক।

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

Local file `files` volume-ত থাকে। Database-ৰ সৈতে একে সময়তে backup লৈ দুয়ো একেলগে restore কৰক:

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

Object storage-ত bucket versioning অন কৰি 35 দিনৰ noncurrent version ৰাখক; তেতিয়া file-ৰ point-in-time recovery bucket-ৰ নিজা কাম।

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