---
title: "Sigurnosne kopije, vraćanje u određeni trenutak i proba oporavka"
description: "Napravite sigurnosnu kopiju Quirea, vratite ga u određeni trenutak i provjerite postupak probom oporavka."
image: "https://docs.quirelms.com/og.png"
---

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

# Sigurnosne kopije, vraćanje u određeni trenutak i proba oporavka

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

Dizajn je opisan u odjeljku 8 dokumenta `docs/architecture/23-ops.md`. Ovo je operativni vodič za Docker Compose proizvod. Napisan je tako da ga može slijediti osoba koja ga nije sastavila; ako neka uputa nije jasna, to je nedostatak ovog dokumenta.

## Šta se štiti i kako <!--quire:what-is-protected-and-how-->

| Resurs | Način zaštite | Lokacija |
| --- | --- | --- |
| Baza podataka | Kontinuirana arhiva WAL-a, najviše svakih 60 sekundi od prvog pokretanja | volumen `pgwal` |
| Baza podataka | Osnovne kopije putem `pg_basebackup`, podrazumijevano dnevno (`backup-scheduler`) | volumen `pgbackup` |
| Baza podataka | Šifrovane kopije osnovnih rezervnih kopija i WAL-a svakih pet minuta (`backup-offsite`) | Posebno spremište koje navedete |
| Datoteke | Volumen `files`. Kopirajte ga alatom za sigurnosne kopije hosta ili koristite verzionisano spremište objekata | volumen `files` |
| Tajne | `docker/.env`, posebno `QUIRE_MASTER_KEY` (i svaki `QUIRE_MASTER_KEY_RETIRED` koji se još koristi), `QUIRE_BACKUP_ENCRYPTION_KEY` i `docker/secrets/audit-signing-key.pem` | Sačuvajte kopiju izvan hosta |
| Indeksi pretrage, keševi, izvedeni sadržaj | Ne prave se sigurnosne kopije; ponovo se izgrađuju | |

Ciljevi: tačka oporavka najviše 60 sekundi prije kvara i vraćanje sistema u roku od 60 minuta za bazu od 500 GB.

Često se prave dvije greške. Baza vraćena **bez datoteka** prikazuje neispravne stranice. Baza vraćena **bez `QUIRE_MASTER_KEY`** ne može dešifrovati SSO, webhook i pristupne podatke integracija; sve dok se ne dovrši rotacija glavnog ključa bez neriješenih vrijednosti ([key-rotation.md](/bs/ops/key-rotation/)), to uključuje i povučene ključeve. Oboje mora biti obuhvaćeno sigurnosnom kopijom.

## Pravljenje sigurnosnih kopija <!--quire:taking-backups-->

Osnovna kopija cijelog klastera:

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

Zadržava se najnovijih `QUIRE_BACKUP_KEEP` osnovnih kopija (podrazumijevano 5), a WAL koji više ne treba najstarijoj se uklanja, pa arhiva ne može rasti bez ograničenja. Na hostu zakažite dnevno pokretanje putem crona ili systemd timera:

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

Ili prepustite planiranje samom stacku: profil `backup` pokreće `backup-scheduler`, koji pravi osnovnu kopiju svakih `QUIRE_BACKUP_INTERVAL_HOURS` (podrazumijevano 24), i `backup-offsite`, opisan u nastavku.

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

## Šifrovane kopije izvan hosta <!--quire:encrypted-off-host-copies-->

Oba volumena nalaze se na istom hostu kao baza, a rezervna kopija na mašini koja je otkazala nije prava kopija. `backup-offsite` kopira svaku osnovnu kopiju i svaki arhivirani WAL segment u zasebno spremište preko porta za pohranu, šifruje ih i zadržava prema politici čuvanja:

- **Šifrovanje.** AES-256-GCM s `QUIRE_BACKUP_ENCRYPTION_KEY` (ili datotekom navedenom u `QUIRE_BACKUP_ENCRYPTION_KEY_FILE`): 32 bajta, dobijena naredbom `openssl rand -hex 32`. Svaka datoteka ima vlastiti nonce i autentifikacijsku oznaku, pa je kopija nečitljiva bez ključa, a svaka izmjena se otkriva. Čuvajte ključ uz `QUIRE_MASTER_KEY`, daleko od ovog hosta i spremišta kopija. Bez ključa nema vraćanja.
- **Lokacija.** `QUIRE_BACKUP_STORAGE_DRIVER` je `s3`, `azure` ili `local` (montirani udaljeni disk na `QUIRE_BACKUP_STORAGE_ROOT`). Koriste se postavke spremišta datoteka s prefiksom `QUIRE_BACKUP_`: `QUIRE_BACKUP_S3_ENDPOINT`, `QUIRE_BACKUP_S3_BUCKET`, `QUIRE_BACKUP_S3_ACCESS_KEY_ID` i tako dalje. Koristite drugu kantu i po mogućnosti drugi račun od onoga za datoteke, s vjerodajnicama koje dozvoljavaju upis, ali ne brisanje, ako pružatelj to podržava.
- **Čuvanje.** Najnovijih `QUIRE_BACKUP_OFFSITE_KEEP` osnovnih kopija (podrazumijevano `QUIRE_BACKUP_KEEP`, inače 7) i WAL potreban najstarijoj; stariji skupovi i segmenti brišu se iz spremišta.
- **Vrijeme.** Svakih `QUIRE_BACKUP_SHIP_INTERVAL_SECONDS` (podrazumijevano 300). Slanje je idempotentno: već sačuvano se preskače, a osnovna kopija smatra se sačuvanom tek kada se na kraju upiše njen manifest.

Iste naredbe mogu se pokrenuti ručno:

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

Za vraćanje na novom hostu prvo vratite kopiju, pa slijedite korake u nastavku koristeći preuzeti direktorij umjesto volumena `pgbackup`, a preuzeti `wal-archive` umjesto `pgwal`:

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

## Vraćanje na određeni trenutak <!--quire:restoring-to-a-point-in-time-->

Koristite ovo nakon gubitka podataka: neuspjelog uvoza, izbrisanog kursa ili migracije uklanjanja koju treba poništiti. Postupak zamjenjuje aktivnu bazu, pa ga prvo uvježbajte probom vraćanja u nastavku.

1. **Odaberite ciljno vrijeme** u UTC-u, neposredno prije oštećenja:
   `2026-09-24 09:30:00+00`. Revizorski dnevnik (`/admin/audit`) obično prikazuje trenutak.
2. **Zaustavite sve što zapisuje**:
   `docker compose -f docker/compose.yaml stop web content worker scheduler collab`
3. **Sačuvajte oštećeni klaster** dok ne provjerite vraćanje:
   ```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. **Raspakujte najnoviju osnovnu kopiju stariju od ciljanog vremena** u volumen podataka i zatražite ciljano vraćanje:
   ```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. **Vratite bazu**: jednom pokrenite Postgres s postavkama za oporavak iz Compose override datoteke, tako da normalna datoteka ostane netaknuta:
   ```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 zamjenjuje cijelu komandu, pa ponavlja dvije postavke potrebne za vraćanje: `max_connections` ne smije biti manji od vrijednosti primarnog servera (inače se oporavak zaustavlja porukom „insufficient parameter settings“) i montirani `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. **Provjerite prije nego što korisnike vratite u sistem**: provjerite revizorski lanac (`docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts`) i da li su izgubljeni podaci vraćeni.
7. **Vratite uobičajeni rad**: `docker compose -f docker/compose.yaml up -d`. Time se Postgres ponovo pokreće s uključenim arhiviranjem i počinje nova WAL vremenska linija. Odmah napravite novu osnovnu sigurnosnu kopiju.

Ime projekta `quire` prefiks je svih volumena; tačna imena prikazuje `docker volume ls`.

## Planirana provjera oporavka <!--quire:the-scheduled-verification-drill-->

`backup-offsite` pokreće probu svakih `QUIRE_BACKUP_DRILL_INTERVAL_HOURS` (podrazumijevano 168, sedmično), kao i pri sljedećem pokretanju nakon neuspjeha. Dohvata najnoviju kopiju izvan hosta i svaki WAL segment nakon nje, dešifruje ih (čime se dokazuje da ključ i dalje otvara podatke i da ništa nije izmijenjeno), poredi svaku datoteku s njenim manifestom, provjerava da arhiva sadrži direktorij podataka Postgresa i da u WAL-u od kopije nadalje nema praznina. Izvještaj se zapisuje u spremište kao `reports/drill-<time>.json` i u evidenciju usluge; neuspjela proba navodi datoteku ili prvi nedostajući segment.

## Proba vraćanja <!--quire:the-restore-drill-->

Sigurnosna kopija koja nikad nije vraćena zapravo nije provjerena kopija. Proba vraća najnoviju potpunu osnovnu kopiju napravljenu prije ciljnog trenutka i WAL arhivu u pomoćni Postgres, koji ne dijeli ništa s aktivnim sistemom, te provjerava rezultat:

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

Cilj je UTC vrijeme u tačno tom obliku. Potrebna je osnovna kopija starija od njega i arhivirani WAL nakon cilja: na novoj instalaciji napravite osnovnu kopiju i pričekajte sljedeći arhivirani segment (najviše minutu ako ima upisa) prije nego što odaberete cilj nakon kopije. Za probu su na hostu potrebni Docker i bash, ništa drugo.

Svaki od ovih koraka može oboriti probu:

1. **Mogućnost oporavka**: pomoćni klaster reprodukuje WAL do cilja i pokreće se.
2. **Potpunost**: brojevi redova u svim tabelama porede se sa živom bazom (`tooling/restore-drill`). Živa baza se promijenila od ciljnog trenutka, pa broj redova u tabeli može odstupati u bilo kojem smjeru za veću vrijednost od 500 redova i desetine njene veličine (upisi povećavaju zaostatak, a brisanja znače da vraćena kopija ima više redova); particija kreirana nakon cilja nije izgubljena tabela. U prometnijoj instalaciji povećajte toleranciju putem `QUIRE_DRILL_MAX_BEHIND` i `QUIRE_DRILL_MAX_DRIFT_RATIO`. Nedostajuća ili ispražnjena tabela znači neuspjeh.
3. **Integritet**: provjerava se hash lanac revizije u vraćenoj kopiji.
4. **Upotrebljivost**: uloga aplikacije čita podatke kroz row-level security.
5. **Vrijeme**: trajanje do uspjeha u odnosu na `QUIRE_DRILL_RTO_SECONDS` (podrazumijevano 3600).

Proba nikada ne zapisuje u živu bazu ni njene volumene: volumeni sigurnosne kopije i WAL-a montirani su samo za čitanje, a pomoćni klaster se na kraju uklanja, bez obzira na ishod.

Postavite `QUIRE_DRILL_REPORT` na putanju za JSON izvještaj koji se zapisuje pri uspjehu ili neuspjehu, pa zakažite pokretanje s Docker hosta:

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

Pokrećite probu mjesečno i prije svake nadogradnje. Jednom u tromjesečju neka je na rezervnom hostu izvede osoba koja nije napisala ovaj vodič i koja koristi samo ovaj dokument.

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

Lokalne datoteke nalaze se u volumenu `files`. Napravite njihovu kopiju istovremeno s bazom i uvijek vraćajte oboje zajedno:

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

Uz spremište objekata uključite verzionisanje kante i zadržite prethodne verzije 35 dana; tako vraćanje datoteka na određeni trenutak obavlja sama kanta.

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