Wiki
Kopie zapasowe i odzyskiwanie
Jak QuoteNode obsługuje kopie zapasowe bazy danych i plików — archiwa szyfrowane age, odtwarzanie sterowane manifestem, zestawy odzyskiwania i profile runtime.
Kopie zapasowe i odzyskiwanie
QuoteNode zawiera wbudowany system kopii zapasowych, który chroni Twoje dane handlowe przed awariami sprzętu, przypadkowym usunięciem i incydentami operacyjnymi.
Co jest objęte kopią zapasową
Każda kopia zapasowa tworzy archiwum zawierające:
- Zrzut bazy danych — pełny zrzut PostgreSQL w formacie niestandardowym (
pg_dump --format=custom), obejmujący wszystkie tabele, sekwencje i ograniczenia. - Magazyn plików — wszystkie przesłane pliki (zdjęcia produktów, logo firm) oraz wygenerowane pliki PDF, zarchiwizowane jako
files.tar.gzze ścieżkami względnymi. - Manifest kopii zapasowej — plik
backup-manifest.jsonzawierający wersję źródłową, tryb szyfrowania, tryb ładunku bazy danych, sumy kontrolne oraz metadane zgodności odtwarzania. - Sumy kontrolne integralności — plik
checksums.sha256zawierający skróty SHA-256 wszystkich komponentów archiwum.
Trzy warstwy szyfrowania
Backup obejmuje trzy niezależne sekrety/ustawienia. „Zaszyfrowany backup” jest niejednoznaczny — zawsze nazywaj warstwę:
- Prywatna tożsamość AGE — odblokowuje wyłącznie zewnętrzne archiwum
.tar.age. Pochodzi z Recovery Kit i jest używana przy odtwarzaniu/weryfikacji (RESTORE_AGE_IDENTITY_FILE). Nie zawiera ani nie zastępujeDB_ENCRYPTION_KEY. DB_ENCRYPTION_KEY— odszyfrowuje polaAPP_ENCRYPTEDw bazie oraz sekrety operacyjne (MFA, SMTP, payloady e-maili ofertowych). Kopię tego klucza przechowuj oddzielnie od archiwum i nigdy nie przekazuj go jako argumentu wiersza poleceń.ENCRYPT_PII— polityka przechowywania w runtime docelowej instancji. Nie odszyfrowuje archiwum; jej zmiana nigdy nie zastępuje właściwego klucza ani postprocessingu odtwarzania.
Sekrety .env / wdrożeniowe oraz Recovery Kit przechowuj w oddzielnych, chronionych lokalizacjach.
Szyfrowanie archiwum
Nowe szyfrowane kopie zapasowe używają szyfrowania odbiorcą age (AGE_RECIPIENT). To jedyny obsługiwany model szyfrowania nowych archiwów.
- Proces tworzenia kopii zapasowej używa wyłącznie publicznego odbiorcy age (
age1...) — do tworzenia kopii nie jest potrzebny żaden klucz prywatny na serwerze. - Szyfrowane archiwa mają rozszerzenie
.tar.age. - Suma kontrolna SHA-256 szyfrowanego archiwum jest przechowywana obok archiwum w celu weryfikacji po stronie operatora.
- Odszyfrowanie wymaga pasującej prywatnej tożsamości age, która jest przechowywana wyłącznie w zestawie odzyskiwania operatora.
- Surowa prywatna tożsamość age nigdy nie jest przechowywana w bazie danych, logach, DTO ani argumentach procesu po potwierdzeniu konfiguracji.
Lokalne kopie nieszyfrowane
Lokalne nieszyfrowane kopie zapasowe (.tar) są dozwolone tylko wtedy, gdy spełnione są wszystkie poniższe warunki:
BACKUP_ARCHIVE_ENCRYPTION_MODE=NONEBACKUP_ALLOW_UNENCRYPTED_LOCAL_BACKUP=true- Miejsce docelowe to magazyn lokalny
BACKUP_DATABASE_PAYLOAD_MODE=APP_ENCRYPTED- Administrator jawnie potwierdził ryzyko w interfejsie
Archiwa nieszyfrowane są blokowane dla magazynu zdalnego oraz dla ładunków z odszyfrowanymi danymi PII.
Konfiguracja (.env). Odbiorca age jest generowany przez Zestaw odzyskiwania (Administracja → Bezpieczeństwo → Backup) i przechowywany w instancji — nie umieszczasz klucza w .env. Ustaw tylko dwie zmienne trybu:
BACKUP_ENABLED=true
# Second, dedicated switch — default off. Set true only on the backup-worker to run scheduled backups.
BACKUP_SCHEDULER_ENABLED=true
BACKUP_ARCHIVE_ENCRYPTION_MODE=AGE_RECIPIENT
BACKUP_DATABASE_PAYLOAD_MODE=APP_ENCRYPTED
# Alternative — encrypted archive + decrypted PII (cross-instance portability):
# BACKUP_DATABASE_PAYLOAD_MODE=PII_DECRYPTED
BACKUP_ALLOW_UNENCRYPTED_LOCAL_BACKUP=false
Aby wyłączyć szyfrowanie archiwum (tylko lokalnie, niezalecane — dane PII nadal pozostają zaszyfrowane w ładunku):
BACKUP_ARCHIVE_ENCRYPTION_MODE=NONE
BACKUP_ALLOW_UNENCRYPTED_LOCAL_BACKUP=true
Przy
AGE_RECIPIENT, jeśli nie wygenerowano jeszcze żadnego odbiorcy, kopia zapasowa kończy się głośnym błędem zamiast zapisać niezabezpieczone archiwum. KombinacjaNONE+PII_DECRYPTEDjest odrzucana.
Tryby ładunku bazy danych
| Tryb | Opis |
|---|---|
APP_ENCRYPTED |
Domyślny. Pola PII pozostają zaszyfrowane kluczem aplikacji DB_ENCRYPTION_KEY. Odtwarzanie na ten sam klucz (zgodny odcisk) nie wymaga dodatkowego kroku; odtwarzanie na inny klucz wymaga oryginalnego klucza źródłowego (przez PII_REKEY_OLD_KEY) do rekeyu offline — w przeciwnym razie odtwarzanie jest blokowane przed jakąkolwiek zmianą. |
PII_DECRYPTED |
Pola PII są odszyfrowywane do tymczasowej bazy danych przed archiwizacją. Skróty haseł użytkowników pozostają bez zmian. Wymaga szyfrowania archiwum AGE_RECIPIENT. Przydatne do przenoszenia między instancjami. |
Podczas odtwarzania kopii PII_DECRYPTED do środowiska docelowego z ENCRYPT_PII=true proces odtwarzania automatycznie ponownie szyfruje dane PII kluczem DB_ENCRYPTION_KEY środowiska docelowego przed normalnym uruchomieniem aplikacji.
Zestaw odzyskiwania
Podczas konfiguracji administrator generuje (lub importuje) odbiorcę age dla szyfrowanych kopii zapasowych. Zestaw odzyskiwania to plik ZIP zawierający:
quotenode-age-identity.txt— prywatna tożsamość age (zwracana tylko raz)quotenode-age-recipient.txt— publiczny odbiorca i odciskquotenode-backup-verify.sh— lokalny skrypt weryfikacyjny (Linux/macOS)quotenode-backup-verify.ps1— lokalny skrypt weryfikacyjny (Windows)README.md— komendy weryfikacji i odtwarzania
Krytyczne: Prywatna tożsamość age jest zwracana tylko raz podczas generowania zestawu. W razie utraty szyfrowane archiwa nie będą mogły zostać odszyfrowane. Przechowuj zestaw odzyskiwania w bezpiecznym miejscu offline.
Administrator musi potwierdzić, że zestaw został zapisany i przetestowany, zanim kreator konfiguracji oznaczy backup jako gotowy do produkcji.
Lokalna weryfikacja kopii zapasowej
Pobrane kopie zapasowe można zweryfikować poza działającą aplikacją za pomocą skryptów z zestawu odzyskiwania:
scripts/quotenode-backup-verify.sh \
--archive /path/backup.tar.age \
--identity /path/quotenode-age-identity.txt \
--expected-sha256 <sha256-from-ui-or-sidecar>
Weryfikator:
- Sprawdza sumę kontrolną SHA-256 szyfrowanego archiwum względem oczekiwanej wartości lub pliku pomocniczego
.sha256. - Odszyfrowuje za pomocą
age -ddo prywatnego katalogu tymczasowego. - Waliduje wpisy tar (odrzuca ścieżki bezwzględne,
.., dowiązania symboliczne, pliki urządzeń). - Sprawdza, czy
backup-manifest.jsonistnieje i ma obsługiwaną wersję. - Uruchamia
sha256sum -c checksums.sha256. - Uruchamia
pg_restore --list db.dump, gdypg_restorejest dostępny. - Domyślnie usuwa odszyfrowane dane tymczasowe (użyj
--keep-decrypted, aby je zachować).
Backup online (domyślny)
Kopie zapasowe online działają, gdy aplikacja obsługuje żądania. Nie ma przestoju.
pg_dumpw formacie niestandardowym tworzy transakcyjnie spójną migawkę bez blokowania tabel ani wstrzymywania zapytań.- Magazyn plików jest archiwizowany równolegle — przesłane pliki i PDF-y są niezmienne po utworzeniu, więc archiwum jest zawsze spójne.
- PostgreSQL nie musi się zatrzymywać, aby uzyskać spójny zrzut bazy danych.
Jak działają kopie zapasowe: wybór topologii
Istnieją dwa sposoby ciągłego uruchamiania zaplanowanych kopii zapasowych. Oba tworzą identyczne archiwa — różnią się jedynie tym, gdzie wykonywane jest zadanie kopii zapasowej.
| Topologia | Kiedy stosować | Kontenery |
|---|---|---|
| Dedykowany worker (domyślnie) | Produkcja. Kopie zapasowe działają w osobnym kontenerze backup-worker, więc nigdy nie rywalizują z ruchem webowym o pamięć ani CPU. |
backend web + backup-worker |
| W procesie | Własne konfiguracje z jednym backendem i własnym plikiem Compose (pakiety wydań go nie używają). Backend web sam wykonuje kopie zapasowe — o jeden kontener mniej do obsługi. | tylko backend web |
Samo zadanie kopii zapasowej to ten sam potok powłoki (pg_dump → archiwizacja → szyfrowanie) w obu przypadkach, uruchamiany poza stertą JVM, więc jego koszt pamięci jest umiarkowany.
Jak wybrać topologię
Dwie zmienne środowiskowe współpracują ze sobą:
JOBS_MODEdecyduje, który kontener faktycznie uruchamia zaplanowane zadanie kopii zapasowej.BACKUP_RUNTIME_PROFILEto etykieta zapisywana w logach i manifestach kopii zapasowych, dzięki której możesz później sprawdzić, jak każda kopia została utworzona.
| Topologia | Backend web | Backup worker |
|---|---|---|
| Dedykowany worker (domyślnie) | JOBS_MODE=web + BACKUP_RUNTIME_PROFILE=WORKER |
kontener JOBS_MODE=backup-only |
| W procesie | JOBS_MODE=all + BACKUP_RUNTIME_PROFILE=WEB_MAINTENANCE |
(brak) |
Pakiety wydań używają topologii dedykowanego workera w każdej instalacji (serwer, LAN, laptop, NAS i Coolify): oba pliki Compose zawierają usługę
backup-workeri ustawiająJOBS_MODEdla każdej usługi. W pakiecie samodzielnym to ustawienie Compose ma pierwszeństwo przed.env, więc tryb w procesie (JOBS_MODE=all+BACKUP_RUNTIME_PROFILE=WEB_MAINTENANCE) wymaga własnego, samodzielnie utrzymywanego pliku Compose.
Dokumentacja profili runtime
BACKUP_RUNTIME_PROFILE przyjmuje cztery wartości. Pierwsze dwie dotyczą powyższych topologii ciągłych; ostatnie dwie dotyczą jednorazowych kopii zapasowych sterowanych przez operatora.
| Profil | Opis |
|---|---|
WORKER |
Domyślny. Stały kontener backup-worker uruchamia zaplanowane kopie zapasowe przez cron. |
WEB_MAINTENANCE |
Backend web wykonuje zaplanowane kopie zapasowe bezpośrednio. Nie jest potrzebny dodatkowy kontener workera. |
ONE_SHOT |
Zewnętrzny cron lub operator uruchamia operator/backup-one-shot.sh i kończy działanie. Brak stałego workera. |
OFFLINE_MAINTENANCE |
Zautomatyzowany skrypt ogłasza przestój, zatrzymuje frontend/backend/backup-worker, utrzymuje działanie PostgreSQL, wykonuje kopię zapasową, restartuje usługi i weryfikuje stan zdrowia. |
Kopia jednorazowa (one-shot)
COMPOSE_PROJECT_NAME=quotenode COMPOSE_FILE=$PWD/docker-compose.yml COMPOSE_ENV_FILE=$PWD/.env \
BACKUP_ARCHIVE_ENCRYPTION_MODE=AGE_RECIPIENT \
BACKUP_AGE_RECIPIENT=age1... \
./operator/backup-one-shot.sh
Konserwacja offline
COMPOSE_PROJECT_NAME=quotenode COMPOSE_FILE=$PWD/docker-compose.yml COMPOSE_ENV_FILE=$PWD/.env \
BACKUP_OFFLINE_NOTICE_SECONDS=300 \
./operator/backup-offline-maintenance.sh
Skrypt konserwacji offline:
- Ogłasza zaplanowaną konserwację (konfigurowalny okres karencji).
- Opcjonalnie włącza statyczną stronę konserwacji na czas wyłączenia usług.
- Zatrzymuje frontend, backend i backup-worker (utrzymuje działanie PostgreSQL).
- Uruchamia kopię jednorazową.
- Restartuje wszystkie usługi.
- Weryfikuje stan zdrowia backendu.
- Zapisuje dziennik konserwacji JSONL na poziomie hosta.
Jeśli skrypt zawiedzie w którymkolwiek momencie, mechanizm bezpieczeństwa automatycznie restartuje usługi.
Użyj --dry-run, aby podejrzeć plan bez wykonywania:
./operator/backup-offline-maintenance.sh --dry-run
Harmonogram
- Domyślny harmonogram: codziennie o 2:00 (
0 0 2 * * *, konfigurowalny przezBACKUP_CRON) - Aktywacja (dwa przełączniki): zaplanowane backupy działają tylko wtedy, gdy ustawione są jednocześnie
BACKUP_ENABLED=trueorazBACKUP_SCHEDULER_ENABLED=true.BACKUP_SCHEDULER_ENABLEDto dedykowany kill-switch, domyślnie wyłączony, dzięki czemu włączenie backupów nigdy nie wywoła niespodziewanego pierwszego zaplanowanego uruchomienia. Ustawiaj go tylko na backup-workerze (profil runtimeWORKER/WEB_MAINTENANCE), nigdy na warstwie web. - Ręczne wyzwalanie: Administratorzy mogą wyzwolić natychmiastową kopię zapasową z panelu administracyjnego lub przez API (
POST /api/v1/admin/backup/trigger). Wyzwalacz zwraca odpowiedź natychmiast (HTTP 202), podczas gdy kopia zapasowa działa asynchronicznie. - Ochrona przed współbieżnością: Blokada oparta na bazie danych zapewnia, że w danym momencie działa tylko jedna kopia zapasowa — we wszystkich workerach i ręcznych wyzwoleniach.
Dla profili ONE_SHOT i OFFLINE_MAINTENANCE wewnętrzny harmonogram jest wyłączony — kopiami zapasowymi zarządza się zewnętrznie.
Opcje magazynu
Magazyn lokalny (domyślny)
Kopie zapasowe są przechowywane w BACKUP_LOCAL_DIR (domyślnie: /app/data/backups), zmapowanym na wolumin Dockera.
W środowisku produkcyjnym lokalne kopie zapasowe powinny być uzupełniane o kopie zdalne.
Magazyn zdalny przez rclone
Jeśli skonfigurowano BACKUP_RCLONE_REMOTE, kopie zapasowe są automatycznie przesyłane do zdalnego miejsca docelowego po utworzeniu lokalnym. rclone obsługuje ponad 70 dostawców magazynu w chmurze, w tym zgodne z S3, Google Cloud Storage, Azure Blob, SFTP i WebDAV.
Pobieranie kopii zapasowych
Pobieranie archiwów kopii zapasowych wymaga autoryzacji podwyższonej (step-up):
- Przejdź do Ustawienia > Backup.
- Kliknij Pobierz przy wpisie kopii zapasowej.
- Wprowadź swoje bieżące hasło (oraz kod TOTP, jeśli włączono MFA).
- System wydaje krótkotrwałe, jednorazowe pozwolenie na pobranie (domyślnie: 120 sekund).
- Archiwum pobiera się automatycznie.
Token pozwolenia jest przechowywany wyłącznie jako skrót SHA-256. Utworzenie pozwolenia i pobranie są audytowane, a pozostali administratorzy są powiadamiani.
Uwaga: Bezpośrednie pobranie bez pozwolenia zwraca 403. Kopie zapasowe w magazynie zdalnym nie mogą być pobierane przez panel administracyjny.
Metadane i ślad audytowy
Każda kopia zapasowa jest śledzona w tabeli backup_logs wraz z:
- Statusem (RUNNING, SUCCESS, FAILED)
- Inicjatorem (SCHEDULER lub ADMIN)
- Czasem rozpoczęcia/zakończenia
- Rozmiarem (w bajtach) i sumą kontrolną SHA-256
- Miejscem docelowym (ścieżka lokalna lub adres URL zdalny)
- Wersją manifestu i wersją aplikacji źródłowej
- Trybem szyfrowania archiwum i odciskiem
- Trybem ładunku bazy danych
- Profilem runtime
- Statusem weryfikacji (NOT_RUN, PASSED, FAILED, SKIPPED_TIMEOUT)
- Statusem testu odtwarzania i statusem zgodności odtwarzania
Odtwarzanie
Użycie operator/restore.sh
Kanoniczny skrypt odtwarzania obsługuje pełny cykl życia:
COMPOSE_PROJECT_NAME=quotenode COMPOSE_FILE_PATH=$PWD/docker-compose.yml COMPOSE_ENV_FILE=$PWD/.env \
DB_USERNAME="$(grep '^DB_USERNAME=' .env | cut -d= -f2-)" \
DB_NAME="$(grep '^DB_NAME=' .env | cut -d= -f2-)" \
DB_PASSWORD="$(grep '^DB_PASSWORD=' .env | cut -d= -f2-)" \
RESTORE_JOURNAL_DIR=$PWD/restore-journal \
RESTORE_AGE_IDENTITY_FILE=/path/to/quotenode-age-identity.txt \
[email protected] \
RESTORE_ADMIN_PASSWORD_FILE=/path/to/password \
./operator/restore.sh /path/to/backup.tar.age
Skrypt:
- Wyodrębnia i waliduje archiwum (manifest, sumy kontrolne, bezpieczeństwo wpisów tar).
- Uruchamia kontrole wstępne (pojemność dysku, wersja PostgreSQL, łączność z bazą danych).
- Tworzy zabezpieczającą kopię docelową przed jakąkolwiek operacją destrukcyjną.
- Zapisuje dziennik odtwarzania na poziomie hosta (JSONL, przetrwa wymianę bazy danych).
- Odtwarza bazę danych.
- Przygotowuje pliki w katalogu tymczasowym i podmienia je na miejsce.
- Zachowuje tożsamość docelową (ID instancji, metadane szyfrowania kopii zapasowych, stan licencji).
- Czyści sesje, publiczne linki ofert i tokeny powiadomień.
- Resetuje lub wymusza zmianę dostępu administratora.
- Ponownie szyfruje dane PII, jeśli kopia jest typu
PII_DECRYPTED, a środowisko docelowe maENCRYPT_PII=true.
Odtwarzanie między instancjami
Podczas odtwarzania kopii zapasowej z innej instalacji domyślnym trybem jest PRESERVE_TARGET_IDENTITY:
- ID instancji docelowej, odbiorca age kopii zapasowych, metadane zestawu odzyskiwania oraz stan licencji są zachowywane.
- Sesje, publiczne linki ofert i tokeny powiadomień są czyszczone.
- Hasło administratora jest resetowane/wymuszana jest jego zmiana.
- Dane biznesowe są w pełni zastępowane (bez scalania).
Zgodność odtwarzania
Kontrola wstępna odtwarzania weryfikuje:
- Starsza kopia do nowszej aplikacji: dozwolone (zgodne).
- Nowsza kopia do starszej aplikacji: zablokowane.
- Brak manifestu: zablokowane.
- Niewłaściwy odcisk klucza szyfrowania dla ładunku
APP_ENCRYPTED: zablokowane przed pracą destrukcyjną. PII_DECRYPTEDbez szyfrowania archiwum: zablokowane.
Decyzje przy odzyskiwaniu i bezpieczne działania
Decyzje polityki restore pochodzą z jednego silnika i zwracają stabilne reason codes; wynik zablokowany niczego nie zmienia.
- APP_ENCRYPTED na inny klucz, bez klucza źródłowego →
SOURCE_DB_ENCRYPTION_KEY_REQUIRED. Podaj oryginalny klucz przezPII_REKEY_OLD_KEY(zmienna środowiskowa, nigdy w argv), aby wykonać rekey. - Błędny klucz źródłowy →
SOURCE_DB_ENCRYPTION_KEY_MISMATCH. Podaj poprawny oryginalny klucz; nie generuj zastępczego. - Cel z PII w postaci jawnej, bez potwierdzenia →
PLAINTEXT_PII_TARGET_NOT_ACKNOWLEDGED. UstawRESTORE_ACKNOWLEDGE_PLAINTEXT_PII=truetylko, jeśli PII w postaci jawnej w spoczynku jest zamierzone. - Brak zweryfikowanego klucza źródłowego (tylko PII_DECRYPTED) → sekrety operacyjne można wyłącznie ZRESETOWAĆ. Ustaw
RESTORE_ACKNOWLEDGE_OPERATIONAL_SECRET_RESET=true, aby to zaakceptować. - Zła AGE identity / błąd integralności → archiwum nie zostaje otwarte i nic nie jest zmieniane.
Konsekwencje resetu sekretów operacyjnych (po zaakceptowaniu): rejestracje MFA są resetowane i użytkownicy muszą je skonfigurować ponownie; SMTP zostaje wyczyszczone, a wychodzące e-maile pozostają wyłączone do czasu rekonfiguracji; nieodzyskiwalne payloady offer-email są scrubowane i nie mogą być ponawiane. FEATURE_2FA_ENABLED=false to wyłącznie awaryjny, tymczasowy break-glass, nigdy normalne ustawienie.
Semantyka wyniku restore:
- Sukces — DB i pliki odtworzone, postprocess krypto wykonany, dopiero potem aplikacja może obsługiwać ruch.
- Odmowa przed mutacją — zablokowana polityka lub nieudany preflight pozostawiają cel bez zmian.
- Udany rollback — awaria po mutacji cofa DB i pliki razem z zapasowej kopii bezpieczeństwa celu.
- Nieudany rollback — aplikacja celowo pozostaje ZATRZYMANA, a wszystkie artefakty recovery są zachowane; odzyskaj z archiwum safety.
Nie wolno: generować losowego zastępczego DB_ENCRYPTION_KEY; przekazywać żadnego sekretu jako argument wiersza poleceń; ani uruchamiać aplikacji web przed zakończeniem postprocessu krypto.
Gwarancja dostępu administratora
Odtwarzanie gwarantuje dostęp administratora za pomocą jednego z:
RESTORE_ADMIN_PASSWORD_FILE— hasło dostarczone przez operatora (ustawiane zforcePasswordChange=true)RESTORE_ADMIN_PASSWORD— wyłącznie do użytku lokalnego/testowego- Automatycznie generowany jednorazowy token resetu — wypisywany na konsolę i do dziennika na poziomie hosta
Uruchomienie próbne (dry run)
RESTORE_DRY_RUN=true ./operator/restore.sh /path/to/backup.tar.age
Waliduje archiwum, sprawdza sumy kontrolne i manifest oraz raportuje plan odtwarzania bez modyfikowania czegokolwiek.
Odzyskiwanie po awarii — odbudowa od zera
Twój serwer przepadł. Masz archiwum kopii zapasowej (.tar.age lub .tar) oraz nowy serwer z Dockerem. Oto jak przeprowadzić odtwarzanie.
Krok 1 — Przygotuj nowy serwer
mkdir quotenode && cd quotenode
Skonfiguruj docker-compose.yml i .env zgodnie z opisem w Przewodniku instalacji.
Krytyczne dla kopii APP_ENCRYPTED: najprościej odtworzyć z tym samym
DB_ENCRYPTION_KEY. Odtworzenie na inny klucz nadal działa, jeśli podasz oryginalny klucz przezPII_REKEY_OLD_KEYdo rekeyu. Bez oryginalnego klucza dane PIIAPP_ENCRYPTEDsą nie do odzyskania (odzyskać można je tylko z archiwumPII_DECRYPTED, a jego sekrety operacyjne trzeba wtedy zresetować) — nigdy nie generuj losowego klucza zastępczego.
Krytyczne dla szyfrowanych archiwów: Potrzebujesz pliku prywatnej tożsamości z zestawu odzyskiwania (
quotenode-age-identity.txt), aby odszyfrować archiwum.
Krok 2 — Skopiuj kopię zapasową i skrypt odtwarzania
scp backup.tar.age user@new-server:~/quotenode/
# operator/restore.sh comes with the release package (the release that created the backup, or a later one)
curl -fsSLO https://quotenode.dev/releases/v0.9.8-alpha/quotenode-deploy-v0.9.8-alpha.tar.gz
tar -xzf quotenode-deploy-v0.9.8-alpha.tar.gz --strip-components=1
Krok 3 — Uruchom odtwarzanie
# Only a successful restore starts the remaining services (the restore itself starts PostgreSQL, the backend and
# the frontend). On failure nothing else starts and the restore's exit status is kept: read its message.
# Default installations keep PII unencrypted at rest (ENCRYPT_PII=false); a restore into such a target requires the
# explicit RESTORE_ACKNOWLEDGE_PLAINTEXT_PII acknowledgement below, for this command only. A target with
# ENCRYPT_PII=true in .env does not use it.
export COMPOSE_PROJECT_NAME=quotenode
COMPOSE_FILE_PATH=$PWD/docker-compose.yml COMPOSE_ENV_FILE=$PWD/.env \
DB_USERNAME="$(grep '^DB_USERNAME=' .env | cut -d= -f2-)" \
DB_NAME="$(grep '^DB_NAME=' .env | cut -d= -f2-)" \
DB_PASSWORD="$(grep '^DB_PASSWORD=' .env | cut -d= -f2-)" \
RESTORE_JOURNAL_DIR=$PWD/restore-journal \
RESTORE_AGE_IDENTITY_FILE=./quotenode-age-identity.txt \
[email protected] \
RESTORE_ADMIN_PASSWORD_FILE=./admin-password \
RESTORE_ACKNOWLEDGE_PLAINTEXT_PII=true \
./operator/restore.sh --fresh-install backup.tar.age \
&& docker compose up -d
Jeśli odtwarzanie zgłosi błąd, nie uruchamiaj QuoteNode ręcznie: wystartowałaby pusta albo niepełnie odtworzona instalacja. Przeczytaj komunikat, usuń przyczynę (na przykład plik tożsamości albo DB_ENCRYPTION_KEY) i uruchom blok ponownie. Jeśli odtwarzanie informuje, że zostawiło aplikację zatrzymaną z zachowanymi artefaktami odzyskiwania, postępuj zgodnie z sekcją Decyzje przy odzyskiwaniu i bezpieczne działania powyżej.
Krok 4 — Zweryfikuj
Otwórz swoją domenę i zaloguj się. Wszyscy klienci, oferty, produkty i ustawienia powinny być dokładnie takie, jakie były w momencie tworzenia kopii zapasowej.
Przetestowane odtwarzanie po awarii
Pełna ścieżka backup → izolowane odtwarzanie jest testowana od początku do końca jako zautomatyzowane ćwiczenie disaster recovery (scenariusze A–G): odtwarzanie z tym samym kluczem, rekey na inny klucz, potwierdzenie PII w postaci jawnej, reset sekretów operacyjnych, odmowa przy błędnej tożsamości oraz rollback po odtwarzaniu. Uruchamia się na prawdziwym PostgreSQL w jednorazowym środowisku i weryfikuje opisane wyżej gwarancje rollbacku oraz obsługi kluczy.
Retencja kopii zapasowych
- Lokalnie: zachowywanych jest
BACKUP_RETENTION_DAILY(domyślnie: 7) najnowszych udanych kopii zapasowych. - Zdalnie: skonfiguruj zasady cyklu życia u swojego dostawcy magazynu.
- Kopie z odszyfrowanymi danymi PII powinny mieć surowszą retencję ze względu na ich wrażliwy charakter.
Limit czasu kopii zapasowej
Każda kopia zapasowa ma konfigurowalny limit czasu (domyślnie: 30 minut przez BACKUP_TIMEOUT_MINUTES). W razie przekroczenia kopia jest przerywana i zapisywana jako FAILED.
Zalecana strategia
- Włącz codzienne automatyczne kopie zapasowe z szyfrowaniem
AGE_RECIPIENTi magazynem zdalnym. - Wygeneruj zestaw odzyskiwania podczas konfiguracji i przechowuj go w bezpiecznym miejscu offline.
- Zweryfikuj swój zestaw odzyskiwania względem rzeczywistej kopii zapasowej za pomocą dołączonych skryptów weryfikujących.
- Okresowo testuj procedury odtwarzania — kopia zapasowa, która nigdy nie została przetestowana, nie jest kopią zapasową.
- Pobierz kopię zapasową co najmniej raz w miesiącu do lokalizacji offline (wymaga autoryzacji step-up).
- Monitoruj status kopii zapasowych w panelu administracyjnym — ostrzeżenia pojawiają się dla nieaktualnych, nieudanych lub nieszyfrowanych kopii.
- Przechowuj co najmniej 7 dni historii kopii zapasowych (wartość domyślna).