---
title: "Αντίγραφα ασφαλείας, επαναφορά σε χρονικό σημείο και άσκηση επαναφοράς"
description: "Δημιουργήστε αντίγραφα ασφαλείας του Quire, επαναφέρετέ το σε συγκεκριμένο χρονικό σημείο και αποδείξτε τη δυνατότητα ανάκτησης με άσκηση επαναφοράς."
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/el/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`. Αυτό είναι το runbook για το προϊόν Docker Compose. Είναι γραμμένο ώστε να μπορεί να το ακολουθήσει κάποιος που δεν το συνέταξε· αν κάποιο βήμα δεν είναι σαφές, αυτό αποτελεί ελάττωμα του εγγράφου.

## Τι προστατεύεται και πώς <!--quire:what-is-protected-and-how-->

| Στοιχείο | Τρόπος | Θέση |
| --- | --- | --- |
| Η βάση δεδομένων | Το WAL αρχειοθετείται συνεχώς, το πολύ κάθε 60 δευτερόλεπτα, από την πρώτη εκκίνηση | Volume `pgwal` |
| Η βάση δεδομένων | Βασικά αντίγραφα ασφαλείας με `pg_basebackup`, καθημερινά από προεπιλογή (`backup-scheduler`) | Volume `pgbackup` |
| Η βάση δεδομένων | Κρυπτογραφημένα αντίγραφα των βασικών αντιγράφων και του WAL, κάθε πέντε λεπτά (`backup-offsite`) | Ξεχωριστός χώρος αποθήκευσης που ορίζετε |
| Αρχεία | Το volume `files`. Αντιγράψτε το με το εργαλείο δημιουργίας αντιγράφων του host ή χρησιμοποιήστε αποθήκευση αντικειμένων με εκδόσεις | Volume `files` |
| Μυστικά | `docker/.env`, κυρίως το `QUIRE_MASTER_KEY` (και τυχόν `QUIRE_MASTER_KEY_RETIRED` που χρησιμοποιείται ακόμη), το `QUIRE_BACKUP_ENCRYPTION_KEY` και το `docker/secrets/audit-signing-key.pem` | Κρατήστε αντίγραφο εκτός αυτού του host |
| Ευρετήρια αναζήτησης, cache και παραγόμενες μορφές | Δεν συμπεριλαμβάνονται σε αντίγραφο ασφαλείας· αναδημιουργούνται | |

Στόχοι: σημείο ανάκτησης εντός 60 δευτερολέπτων πριν από τη βλάβη και επαναφορά μέσα σε 60 λεπτά για βάση δεδομένων 500 GB.

Συμβαίνουν συχνά δύο λάθη. Μια βάση δεδομένων που επαναφέρεται **χωρίς τα αρχεία της** εμφανίζει κατεστραμμένες σελίδες. Μια βάση δεδομένων που επαναφέρεται **χωρίς το `QUIRE_MASTER_KEY`** δεν μπορεί να αποκρυπτογραφήσει τα διαπιστευτήρια SSO, webhook και ενσωματώσεων που περιέχει. Μέχρι να ολοκληρωθεί περιστροφή κύριου κλειδιού χωρίς ανεπίλυτες τιμές ([key-rotation.md](/el/ops/key-rotation/)), αυτό ισχύει και για τα αποσυρμένα κλειδιά. Και τα δύο πρέπει να περιλαμβάνονται στο αντίγραφο ασφαλείας.

## Δημιουργία αντιγράφων ασφαλείας <!--quire:taking-backups-->

Ένα βασικό αντίγραφο ασφαλείας ολόκληρου του cluster:

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

Διατηρεί τα πιο πρόσφατα `QUIRE_BACKUP_KEEP` βασικά αντίγραφα (προεπιλογή 5) και διαγράφει το WAL που δεν χρειάζεται πλέον το παλαιότερο, ώστε το αρχείο να μην μπορεί να αυξηθεί απεριόριστα. Προγραμματίστε το καθημερινά με cron ή χρονοδιακόπτη systemd στον 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
```

Ή αφήστε τον stack να το προγραμματίσει: το προφίλ `backup` εκτελεί το `backup-scheduler`, το οποίο δημιουργεί βασικό αντίγραφο κάθε `QUIRE_BACKUP_INTERVAL_HOURS` (προεπιλογή 24), και το `backup-offsite` που περιγράφεται παρακάτω.

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

## Κρυπτογραφημένα αντίγραφα εκτός host <!--quire:encrypted-off-host-copies-->

Και τα δύο volume βρίσκονται στον ίδιο host με τη βάση δεδομένων, και ένα αντίγραφο ασφαλείας στον υπολογιστή που χάλασε δεν είναι αντίγραφο ασφαλείας. Το `backup-offsite` αντιγράφει κάθε βασικό αντίγραφο και κάθε αρχειοθετημένο τμήμα WAL σε ξεχωριστό χώρο αποθήκευσης μέσω της θύρας αποθήκευσης, τα κρυπτογραφεί και τα διατηρεί εκεί σύμφωνα με την πολιτική διατήρησης:

- **Κρυπτογράφηση.** AES-256-GCM με `QUIRE_BACKUP_ENCRYPTION_KEY` (ή το αρχείο που ονομάζεται από το `QUIRE_BACKUP_ENCRYPTION_KEY_FILE`): 32 byte, από `openssl rand -hex 32`. Κάθε αρχείο έχει δικό του nonce και ετικέτα ελέγχου ταυτότητας, επομένως το αντίγραφο δεν διαβάζεται χωρίς το κλειδί και ανιχνεύεται κάθε αλλαγή. Κρατήστε το κλειδί μαζί με το `QUIRE_MASTER_KEY`, μακριά από αυτόν τον host και τον χώρο αντιγράφων ασφαλείας. Χωρίς το κλειδί δεν μπορεί να γίνει επαναφορά.
- **Θέση.** Το `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). Η αποστολή είναι ιδιοδύναμη: παραλείπονται όσα έχουν αποθηκευτεί ήδη, ενώ ένα βασικό αντίγραφο θεωρείται αποθηκευμένο μόνο όταν γραφτεί τελευταίο το 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
```

Για επαναφορά σε νέο host, ανακτήστε πρώτα ένα σύνολο και έπειτα ακολουθήστε τα βήματα παρακάτω, χρησιμοποιώντας τον ανακτημένο κατάλογο αντί του volume `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. **Κρατήστε τον κατεστραμμένο 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. **Αποσυσκευάστε το πιο πρόσφατο βασικό αντίγραφο πριν από τον στόχο** στο 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, δηλαδή εβδομαδιαία), καθώς και στον επόμενο κύκλο μετά από αποτυχία. Ανακτά το πιο πρόσφατο βασικό αντίγραφο εκτός host και κάθε τμήμα 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 στον host.

Κάθε βήμα μπορεί να αποτύχει την άσκηση:

1. **Δυνατότητα ανάκτησης**: το δοκιμαστικό cluster εφαρμόζει το WAL έως τον στόχο και ανοίγει.
2. **Πληρότητα**: συγκρίνεται ο αριθμός γραμμών κάθε πίνακα με τη ζωντανή βάση δεδομένων (`tooling/restore-drill`). Η ζωντανή βάση έχει προχωρήσει από τον στόχο, οπότε ένας πίνακας μπορεί να διαφέρει προς οποιαδήποτε κατεύθυνση κατά τη μεγαλύτερη τιμή ανάμεσα στις 500 γραμμές και στο ένα δέκατο του μεγέθους του (οι εγγραφές την αφήνουν πίσω, οι διαγραφές κάνουν την επαναφορά να έχει περισσότερες γραμμές). Ένα διαμέρισμα που δημιουργήθηκε μετά τον στόχο δεν θεωρείται χαμένος πίνακας. Αυξήστε την ανοχή σε πιο φορτωμένη εγκατάσταση με τα `QUIRE_DRILL_MAX_BEHIND` και `QUIRE_DRILL_MAX_DRIFT_RATIO`. Η απουσία ή το άδειασμα πίνακα προκαλεί αποτυχία.
3. **Ακεραιότητα**: επαληθεύεται η αλυσίδα hash ελέγχου στο αντίγραφο που επαναφέρθηκε.
4. **Χρηστικότητα**: ο ρόλος εφαρμογής διαβάζει μέσω row-level security.
5. **Χρόνος**: από την εκκίνηση έως την επιτυχία, σε σύγκριση με το `QUIRE_DRILL_RTO_SECONDS` (προεπιλογή 3600).

Δεν γράφει ποτέ στη ζωντανή βάση ή στα volume της: τα volume αντιγράφων και WAL προσαρτώνται μόνο για ανάγνωση, ενώ ο δοκιμαστικός cluster διαγράφεται στο τέλος, είτε περάσει είτε αποτύχει.

Ορίστε το `QUIRE_DRILL_REPORT` σε διαδρομή για να γραφτεί αρχείο αναφοράς JSON, ανεξάρτητα από το αποτέλεσμα, και προγραμματίστε την εκτέλεση από τον Docker host:

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

Εκτελείτε την άσκηση κάθε μήνα και πριν από κάθε αναβάθμιση. Μια αποτυχημένη άσκηση εμποδίζει την αναβάθμιση. Μία φορά το τρίμηνο, ζητήστε από κάποιον που δεν συνέταξε αυτό το runbook να εκτελέσει πραγματική επαναφορά σε συγκεκριμένο χρονικό σημείο σε εφεδρικό host, ακολουθώντας μόνο αυτό το έγγραφο.

## Αρχεία <!--quire:files-->

Τα τοπικά αρχεία βρίσκονται στο volume `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 .
```

Με αποθήκευση αντικειμένων ενεργοποιήστε την έκδοση κάδου και διατηρήστε τις μη τρέχουσες εκδόσεις για 35 ημέρες· έτσι η ανάκτηση αρχείων σε συγκεκριμένο χρονικό σημείο γίνεται από τον ίδιο τον κάδο.

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