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
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), to uključuje i povučene ključeve. Oboje mora biti obuhvaćeno sigurnosnom kopijom.
Pravljenje sigurnosnih kopija
Osnovna kopija cijelog klastera:
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:
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.
docker compose -f docker/compose.yaml --profile backup up -d
Šifrovane kopije izvan hosta
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:
docker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts shipdocker 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:
bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore
Vraćanje na određeni trenutak
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.
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.
Zaustavite sve što zapisuje:
docker compose -f docker/compose.yaml stop web content worker scheduler collab
Sačuvajte oštećeni klaster dok ne provjerite vraćanje:
docker compose -f docker/compose.yaml stop postgresdocker run --rm -v quire_postgres18-data:/from -v quire_postgres-damaged:/to alpine cp -a /from/. /to/
Raspakujte najnoviju osnovnu kopiju stariju od ciljanog vremena u volumen podataka i zatražite ciljano vraćanje:
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'
Vratite bazu: jednom pokrenite Postgres s postavkama za oporavak iz Compose override datoteke, tako da normalna datoteka ostane netaknuta:
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.
docker compose -f docker/compose.yaml -f docker/compose.recover.yaml up -d postgresdocker compose -f docker/compose.yaml logs -f postgres # wait for "database system is ready"
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.
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
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
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:
docker/scripts/restore-drill.sh # to ninety minutes agodocker/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:
Mogućnost oporavka: pomoćni klaster reprodukuje WAL do cilja i pokreće se.
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.
Integritet: provjerava se hash lanac revizije u vraćenoj kopiji.
Upotrebljivost: uloga aplikacije čita podatke kroz row-level security.
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:
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
Lokalne datoteke nalaze se u volumenu files. Napravite njihovu kopiju istovremeno s bazom i uvijek vraćajte oboje zajedno:
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.