---
title: "बैकअप, समय-बिंदु पुनर्प्राप्ति और पुनर्स्थापन अभ्यास"
description: "Quire का बैकअप लें, उसे समय-बिंदु पर पुनर्स्थापित करें और अभ्यास से इसकी पुष्टि करें।"
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/hi/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` वॉल्यूम |
| डेटाबेस | `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 सेकंड के भीतर का पुनर्प्राप्ति बिंदु, और 500 GB डेटाबेस के लिए 60 मिनट के भीतर पुनर्स्थापन।

दो गलतियाँ आम हैं। फ़ाइलों के बिना पुनर्स्थापित डेटाबेस टूटे हुए पृष्ठ दिखाता है। `QUIRE_MASTER_KEY` के बिना पुनर्स्थापित डेटाबेस अपने SSO, webhook और integration क्रेडेंशियल डिक्रिप्ट नहीं कर सकता; जब तक मास्टर कुंजी रोटेशन पूरा न हो और कुछ भी अनसुलझा न रहे ([key-rotation.md](/hi/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 खंड को storage port से अलग संग्रह में एन्क्रिप्ट करके कॉपी करता है और वहाँ प्रतिधारण नीति के अनुसार रखता है:

- **एन्क्रिप्शन।** `QUIRE_BACKUP_ENCRYPTION_KEY` (या `QUIRE_BACKUP_ENCRYPTION_KEY_FILE` से बताई फ़ाइल) के साथ AES-256-GCM: `openssl rand -hex 32` से बनाए गए 32 bytes। हर फ़ाइल का अपना nonce और authentication tag होता है, इसलिए कुंजी के बिना प्रति पढ़ी नहीं जा सकती और उसमें बदलाव पकड़ा जाता है। कुंजी को `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)। भेजने की प्रक्रिया idempotent है: जो पहले से संग्रह में है उसे छोड़ देती है और बेस बैकअप को तभी संग्रहित मानती है जब अंत में उसका manifest लिखा गया हो।

हाथ से चलाने पर भी यही कमांड है:

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

डेटा खोने पर इसका उपयोग करें: गलत import, हटाया पाठ्यक्रम, या ऐसी contract migration जिसे वापस लेना है। यह चालू डेटाबेस बदलता है, इसलिए पहले नीचे के अभ्यास में इसे आज़माएँ।

1. **लक्ष्य समय चुनें**, क्षति से ठीक पहले का 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. **पुनर्स्थापन सत्यापित होने तक क्षतिग्रस्त क्लस्टर रखें**:
   ```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. **पुनर्प्राप्त करें**: सामान्य फ़ाइल को छुए बिना Compose override के जरिए रिकवरी सेटिंगों सहित 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 बदलता है, इसलिए रिकवरी की निर्भर दो सेटिंगें भी दोहराएँ: `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. **किसी को प्रवेश देने से पहले जाँचें**: audit chain
   (`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 archiving चालू करके फिर शुरू होता है और WAL की नई timeline आरंभ होती है। तुरंत नया बेस बैकअप लें।

प्रोजेक्ट नाम `quire` हर वॉल्यूम के आगे जुड़ता है; सटीक नाम `docker volume ls` दिखाता है।

## नियोजित सत्यापन अभ्यास <!--quire:the-scheduled-verification-drill-->

`backup-offsite` हर `QUIRE_BACKUP_DRILL_INTERVAL_HOURS` घंटे (डिफ़ॉल्ट 168, यानी साप्ताहिक) अभ्यास चलाता है, और विफलता के बाद अगले चक्र में फिर चलाता है। यह नवीनतम होस्ट-बाहरी बेस बैकअप और उसके बाद के सभी WAL खंड लाता है, हर एक को डिक्रिप्ट करता है (इससे पुष्टि होती है कि कुंजी अब भी खोलती है और बदलाव नहीं हुआ), प्रत्येक फ़ाइल को उसके manifest से मिलाता है, जाँचता है कि संग्रह 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. **पुनर्प्राप्ति क्षमता**: अस्थायी क्लस्टर लक्ष्य समय तक WAL लागू करके खुलता है।
2. **पूर्णता**: चालू डेटाबेस से हर तालिका की पंक्ति-संख्या की तुलना (`tooling/restore-drill`)। चालू डेटाबेस लक्ष्य से आगे बढ़ चुका है, इसलिए किसी तालिका में दोनों दिशाओं में 500 पंक्तियों और उसके आकार के दसवें हिस्से में से अधिकतम अंतर स्वीकार्य है (लिखाइयों से पुनर्स्थापन पीछे रह सकता है, मिटाने से उसमें अधिक पंक्तियाँ रह सकती हैं); लक्ष्य के बाद बना partition खोई तालिका नहीं। अधिक व्यस्त इंस्टॉल में `QUIRE_DRILL_MAX_BEHIND` और `QUIRE_DRILL_MAX_DRIFT_RATIO` से सीमा बढ़ाएँ। अनुपस्थित या खाली तालिका विफल होती है।
3. **अखंडता**: पुनर्स्थापित प्रति में audit hash chain सत्यापित होती है।
4. **उपयोगिता**: application role row-level security के जरिए पढ़ती है।
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 versioning चालू करें और 35 दिन तक अप्रचलित संस्करण रखें; तब फ़ाइलों की समय-बिंदु पुनर्प्राप्ति bucket संभालता है।

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