SSD Nodes Learn Hosting plans →
Przewodniki Matt ConnorAutor: Matt Connor

Jak wykonać kopię zapasową VPS za pomocą Restic

Konfiguracja Restic na Ubuntu 24.04 pozwala na bezpieczne przesyłanie zaszyfrowanych danych do zdalnego repozytorium. Artykuł wyjaśnia automatyzację przez systemd i retencję.

Dlaczego kopia zapasowa na tym samym serwerze nie jest kopią zapasową

Restic to darmowe, otwartoźródłowe narzędzie do tworzenia kopii zapasowych, które wysyła zaszyfrowane i zdeduplikowane migawki plików do zewnętrznego repozytorium: na drugi serwer VPS, maszynę domową lub pamięć obiektową zgodną z S3. Niniejszy przewodnik opisuje konfigurację na systemie Ubuntu 24.04, począwszy od instalacji, przez repozytorium SFTP, wykonanie pierwszej kopii, aż po harmonogram systemd, politykę retencji oraz procedurę przywracania danych, która potwierdza poprawność całego procesu. Miejsce docelowe musi znajdować się na innej maszynie, ponieważ kopia przechowywana na tym samym serwerze ginie wraz z nim.

Katalog backup/ na serwerze, z którego tworzona jest kopia, chroni wyłącznie przed przypadkowym usunięciem pliku. Nie przetrwa on awarii dysku, ponieważ znajduje się na tym samym nośniku. Nie oprze się atakującemu z uprawnieniami root, ponieważ usunie on kopie w pierwszej kolejności. Nie zabezpieczy również przed błędem na koncie, który skutkuje usunięciem samego serwera VPS. Najmniej wydajne centrum danych na świecie żartuje z archiwum tar o nazwie backup_final_v2_REAL, które znajduje się na tej samej macierzy co dane – ten żart jest trafny, ponieważ wielu z nas dokładnie tak postępowało. Zasada brzmi: dane muszą znajdować się poza serwerem, a restic jest najmniej uciążliwym sposobem na jej przestrzeganie.

Restic w czterech punktach

Repozytorium. Miejsce, do którego restic zapisuje dane. Jest to katalog w formacie restic, wypełniony zaszyfrowanymi blokami danych, które może odczytać tylko restic. Nie należy edytować go ręcznie; komunikacja odbywa się za pomocą poleceń restic oraz adresu -r.

Migawka (Snapshot). Obraz plików z wybranego momentu. Każde uruchomienie kopii zapasowej tworzy migawkę. Każda migawka może zostać przywrócona niezależnie i zachowuje się jak kompletna kopia danych z danej chwili.

Deduplikacja. Restic dzieli pliki na fragmenty (chunks) na podstawie ich zawartości i przesyła tylko te, których w repozytorium jeszcze nie ma. Pierwsza kopia zapasowa przesyła wszystko; każda kolejna przesyła tylko to, co uległo zmianie. Nocna migawka o rozmiarze 20 GB, w której zmieniło się 50 MB, zajmuje około 50 MB, dlatego przechowywanie dziesiątek migawek jest tanie.

Szyfrowanie domyślne. Repozytorium restic jest zawsze szyfrowane (AES-256). Restic odmawia utworzenia lub otwarcia repozytorium z pustym hasłem, chyba że użyjesz flagi --insecure-no-password (w restic 0.17.0 i nowszych). Repozytorium skonfigurowane zgodnie z tym przewodnikiem wymaga podania hasła przy każdym poleceniu. Host kopii zapasowej lub dostawca pamięci masowej widzi tylko zaszyfrowane bloki danych. Konsekwencja jest surowa: utrata hasła oznacza trwałą utratę danych. Przechowuj kopię hasła w miejscu innym niż ten serwer. Jest to na tyle istotne, że kwestia ta pojawia się poniżej jeszcze dwukrotnie.

Instalacja restic na Ubuntu 24.04

sudo apt update && sudo apt install -y restic
restic version

W systemie Ubuntu 24.04 powyższa procedura instaluje restic w wersji 0.16.4, podczas gdy aktualne wydanie upstream to 0.19.1. Rozbieżność wynika z faktu, że wydania LTS (long term support) zamrażają wersje pakietów, co w tym przypadku nie ma znaczenia: wersja 0.16.4 realizuje wszystkie zadania opisane w tym przewodniku. Jeśli wymagane jest najnowsze wydanie ze względu na poprawę wydajności, należy pobrać oficjalny plik binarny ze strony wydań projektu restic w serwisie GitHub, rozpakować go za pomocą bunzip2 i zainstalować w /usr/local/bin/restic; instalacja restic nie wymaga żadnych dodatkowych kroków.

Utworzenie repozytorium na innym serwerze przez SFTP

Wymagana jest maszyna docelowa: zazwyczaj wystarcza drugi, niewielki VPS lub dowolny serwer z uruchomionym SSH i wolnym miejscem na dysku. Restic obsługuje protokół SFTP (przesyłanie plików przez SSH), więc na hoście docelowym nie trzeba instalować żadnego dodatkowego oprogramowania. W tym przewodniku hostem kopii zapasowej jest 10.0.0.12 z użytkownikiem restic. Nie należy nazywać tego użytkownika backup: systemy Ubuntu i Debian domyślnie tworzą zarezerwowane konto systemowe o nazwie backup (uid 34, bez powłoki logowania), dlatego adduser backup zakończy się niepowodzeniem, a ssh backup@... trafi do nologin.

Zadanie wykonywane w nocy będzie uruchamiane jako root na serwerze źródłowym, dlatego użytkownik root musi mieć możliwość logowania się do hosta docelowego przy użyciu klucza. Należy utworzyć dedykowany klucz bez hasła, ponieważ o godzinie 3:00 rano nikt nie będzie obecny, aby je wpisać, a następnie skopiować klucz:

sudo ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N "" -C "web1-restic"
sudo ssh-copy-id -i /root/.ssh/id_ed25519.pub restic@10.0.0.12
sudo ssh restic@10.0.0.12 true && echo key login works

Jeśli obsługa kluczy jest nowym zagadnieniem, podstawy zarządzania kluczami SSH wyjaśniają ten model, uprawnienia oraz sposób późniejszego unieważnienia klucza.

Następnie należy przygotować hasło do repozytorium. Wygeneruj silne hasło i zapisz je w pliku dostępnym tylko dla użytkownika root:

openssl rand -base64 32 | sudo tee /root/.restic-password
sudo chmod 600 /root/.restic-password

Przed kontynuowaniem skopiuj to hasło do menedżera haseł. W przypadku awarii serwera VPS, repozytorium wraz z tym hasłem pozwoli na pełne odzyskanie danych; samo repozytorium bez hasła jest bezużyteczne.

Zainicjuj repozytorium:

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password init
created restic repository 9f3c2a1b0d at sftp:restic@10.0.0.12:/srv/restic/web1

Alternatywnym miejscem docelowym jest pamięć obiektowa zgodna z S3, co stanowi właściwy wybór, gdy nie chcesz utrzymywać drugiej maszyny. Każdy bucket zgodny z S3 działa w ten sam sposób; zmienia się jedynie adres oraz dwie zmienne z danymi uwierzytelniającymi:

export AWS_ACCESS_KEY_ID=your-key-id
export AWS_SECRET_ACCESS_KEY=your-secret-key
sudo -E restic -r s3:https://s3.example.com/web1-backups --password-file /root/.restic-password init

Wszystkie kroki po init są identyczne dla obu typów lokalizacji. Reszta tego przewodnika zakłada użycie adresu SFTP; należy podstawić własne dane.

Pierwsza kopia zapasowa z wykluczeniami

Należy tworzyć kopie zapasowe danych, których nie można zainstalować ponownie, a nie całego systemu plików. System operacyjny można odtworzyć poprzez ponowną instalację; konfiguracja i dane użytkownika nie. W przypadku typowego VPS oznacza to /etc, /home oraz lokalizacje, w których aplikacje przechowują swój stan, takie jak /srv lub /var/www. Należy wykluczyć pamięci podręczne (cache), ponieważ zajmują dużo miejsca, ulegają ciągłym zmianom i są odtwarzane automatycznie:

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password backup /etc /home /srv --exclude '/home/*/.cache'
Files:        4181 new,     0 changed,     0 unmodified
Added to the repository: 731.204 MiB (312.418 MiB stored)
snapshot 5b8a3f2c saved

Pierwsze uruchomienie przesyła wszystkie dane, więc trwa dłużej. Ponowne wykonanie tego samego polecenia kończy się w kilka sekund, raportując zmianę kilku plików i dodanie kilku MiB, ponieważ deduplikacja przesyła tylko nowe fragmenty danych. Wyświetlanie listy posiadanych kopii:

sudo restic -r sftp:restic@10.0.0.12:/srv/restic/web1 --password-file /root/.restic-password snapshots

Każdy snapshot posiada identyfikator, czas utworzenia oraz listę zawartych w nim ścieżek. Identyfikatory te służą do przywracania danych.

Wykonywanie zadań w nocy za pomocą systemd timer

Wpisywanie adresu repozytorium przy każdym poleceniu staje się uciążliwe, a kopia zapasowa wykonywana ręcznie przestaje być tworzona w ciągu miesiąca. Oba problemy rozwiązuje jeden skrypt i jeden timer. Skrypt ustawia dwie zmienne środowiskowe odczytywane przez restic, RESTIC_REPOSITORY oraz RESTIC_PASSWORD_FILE, dzięki czemu każde polecenie wewnątrz pozostaje krótkie:

sudo nano /usr/local/bin/restic-backup.sh
#!/usr/bin/env bash
set -euo pipefail
export RESTIC_REPOSITORY='sftp:restic@10.0.0.12:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password

restic backup /etc /home /srv --exclude '/home/*/.cache'
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check
sudo chmod 700 /usr/local/bin/restic-backup.sh

Linie forget oraz check zostały wyjaśnione w dwóch kolejnych sekcjach. Teraz harmonogram: usługa oneshot, która uruchamia skrypt, oraz timer, który wyzwala go codziennie o godzinie 03:00. Timer jest lepszy od wpisu w cron, ponieważ loguje przebieg do journal, a Persistent=true uruchamia pominiętą kopię zapasową natychmiast po przywróceniu działania serwera po przestoju.

# /etc/systemd/system/restic-backup.service
[Unit]
Description=Nightly restic backup
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/restic-backup.sh
# /etc/systemd/system/restic-backup.timer
[Unit]
Description=Run the nightly restic backup

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=15m
Persistent=true

[Install]
WantedBy=timers.target

Włącz timer, a następnie uruchom usługę ręcznie i obserwuj jej działanie:

sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
sudo systemctl start restic-backup.service
sudo journalctl -u restic-backup.service -f

systemctl list-timers pokazuje, kiedy nastąpi kolejne uruchomienie. Można również wygenerować parę plików jednostek zamiast wpisywać je ręcznie:

ToolGenerate the backup service and timer

Pełny schemat dotyczący tych dwóch plików, w tym składnia kalendarza oraz dyrektywy utwardzające, które może zawierać usługa, znajduje się w uruchamianie programu jako usługa systemd na VPS.

Kopia zapasowa to tylko plotka, dopóki jej nie przywrócisz

Traktuj to zdanie jak przykazanie. Zadanie kopii zapasowej, które kończy się sukcesem każdej nocy, dowodzi jedynie, że zadanie zostało wykonane; nie dowodzi, że dane można odzyskać. Dwie procedury sprawdzające eliminują to ryzyko.

Po pierwsze, restic check, które skrypt wykonuje już każdej nocy. Weryfikuje ono strukturę repozytorium oraz indeks, dzięki czemu ciche uszkodzenia na hoście kopii zapasowej zostaną wykryte następnej nocy, a nie w dniu próby przywrócenia danych. Raz w miesiącu uruchom pełniejszą wersję, która pobiera i kryptograficznie weryfikuje losową dziesiątą część rzeczywistych danych:

sudo -i
export RESTIC_REPOSITORY='sftp:restic@10.0.0.12:/srv/restic/web1'
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic check --read-data-subset=10%

Ponieważ podzbiór jest wybierany losowo przy każdym uruchomieniu, dokumentacja restic wyraźnie zaznacza, że powtarzane uruchomienia nie gwarantują sprawdzenia każdego pliku typu pack. Jeśli chcesz, aby comiesięczne uruchomienia sprawdzały całe repozytorium bez konieczności pobierania wszystkich danych, użyj formy z grupami: --read-data-subset=1/10 w jednym miesiącu, 2/10 w kolejnym i tak dalej, aż do 10/10. Restic dzieli pliki pack na dziesięć w przybliżeniu równych grup i sprawdza tylko grupę n, więc pełny cykl dziesięciu uruchomień odczytuje każdą grupę raz.

Po drugie, ćwiczenie przywracania danych. Nadal w powłoce root, przywróć jeden rzeczywisty katalog z najnowszej migawki do tymczasowej lokalizacji i porównaj go z aktywnymi plikami:

restic restore latest --target /srv/restore-drill --include /etc/ssh
diff -r /etc/ssh /srv/restore-drill/etc/ssh

diff brak danych wyjściowych oznacza, że każdy bajt został przywrócony identycznie, co jest jedynym wiarygodnym dowodem. Następnie usuń /srv/restore-drill. Wykonuj to ćwiczenie co miesiąc, a raz lub dwa razy w roku przeprowadź pełną wersję: przywróć całą najnowszą migawkę na tymczasowy VPS i sprawdź, czy aplikacja faktycznie się z niej uruchamia. W dniu, w którym będziesz musiał to zrobić pod presją czasu, chcesz, aby była to procedura, którą już znasz.

Retencja: forget oraz prune

Bez zdefiniowanej polityki migawki gromadzą się w nieskończoność, a rozmiar repozytorium stale rośnie. Linia forget w skrypcie stosuje politykę każdej nocy: --keep-daily 7 zachowuje jedną migawkę dziennie z ostatnich siedmiu dni, --keep-weekly 4 jedną tygodniowo z czterech tygodni, a --keep-monthly 6 jedną miesięcznie z sześciu miesięcy. Wszystkie migawki nieobjęte regułami są usuwane z indeksu.

Samo forget usuwa jedynie wpisy o migawkach; fragmenty danych pozostają w repozytorium, dopóki nie zostaną usunięte. Do tego służy --prune: wyszukuje fragmenty, do których nie odwołuje się żadna migawka, i usuwa je, co pozwala na odzyskanie miejsca na dysku. Operacja prune obciąża repozytorium, dlatego w przypadku dużych zbiorów danych niektórzy uruchamiają forget co noc, a --prune raz w tygodniu; przy typowych rozmiarach VPS codzienne uruchamianie jest dopuszczalne.

Bazy danych: najpierw zrzut, potem kopia zapasowa

Restic kopiuje pliki w trakcie ich odczytu, podczas gdy baza danych zapisuje dane w sposób ciągły. Plik aktywnej bazy danych przechwycony w trakcie zapisu po przywróceniu będzie uszkodzony, ponieważ kopia zawiera wymieszane strony sprzed i po operacji zapisu. Rozwiązanie jest standardowe: należy wymusić na silniku bazy danych wygenerowanie spójnego eksportu do pliku, a następnie pozwolić narzędziu restic na wykonanie kopii zapasowej tego pliku.

W przypadku PostgreSQL należy dodać linię ze zrzutem na początku pliku restic-backup.sh, przed poleceniem restic backup, oraz uwzględnić katalog ze zrzutem w ścieżkach kopii zapasowej:

mkdir -p /var/backups/db
sudo -u postgres pg_dump myapp | gzip > /var/backups/db/myapp.sql.gz

mysqldump pełni tę samą rolę w przypadku MariaDB oraz MySQL. Jako przykład praktycznego zastosowania całego schematu, sekcja dotycząca kopii zapasowej Nextcloud włącza tryb konserwacji, wykonuje zrzut Postgres i kopiuje pliki jako jeden spójny zestaw – dokładnie taki, jaki restic powinien każdej nocy przesyłać poza serwer. W przypadku SQLite zasada jest podobna, choć stosuje się prostsze środki: przewodnik po Vaultwarden zatrzymuje kontener na kilka sekund, aby wykonać kopię „na zimno” pliku db.sqlite3, a to właśnie to archiwum jest przesyłane przez restic poza serwer.

FAQ

Czy kopie zapasowe restic są szyfrowane?

Tak, zawsze. Każde repozytorium restic jest szyfrowane za pomocą AES-256 i nie istnieje tryb bez szyfrowania. Restic odmawia również użycia pustego hasła, chyba że użyjesz --insecure-no-password (dostępne od wersji restic 0.17.0), więc repozytorium skonfigurowane zgodnie z tym przewodnikiem wymaga hasła przy każdym poleceniu. Maszyna lub dostawca przechowujący repozytorium posiada tylko zaszyfrowane bloki danych, więc naruszenie bezpieczeństwa hosta kopii zapasowej nie ujawnia Twoich plików. Zasada jest bezwzględna: bez hasła danych nie odzyska nikt, więc przechowuj jego kopię z dala od serwera.

Czy restic wykonuje kopie przyrostowe?

Każda migawka restic zachowuje się jak pełna kopia zapasowa, kosztując tyle, co kopia przyrostowa. Restic dzieli pliki na fragmenty i przesyła tylko te, których repozytorium jeszcze nie przechowuje, więc nocne uruchomienie przesyła tylko to, co zmieniło się danego dnia. W przeciwieństwie do tradycyjnych schematów przyrostowych, nie ma tu łańcucha zależności: każdą migawkę można przywrócić bezpośrednio, a usunięcie starej migawki nigdy nie uszkodzi nowszej.

Jak przywrócić pliki z kopii zapasowej restic?

Uruchom restic snapshots, aby znaleźć identyfikator migawki, a następnie restic restore <id> --target /some/empty/dir, aby ją przywrócić, dodając --include /path, aby przywrócić tylko jej część. latest działa zamiast identyfikatora. Restic odtwarza oryginalną strukturę katalogów w miejscu docelowym, więc przywrócenie /etc/ssh trafi do /some/empty/dir/etc/ssh. Przećwicz to, zanim będzie Ci potrzebne, ponieważ niesprawdzona kopia zapasowa to tylko plotka.

Jak często powinienem uruchamiać kopię zapasową restic?

Dla serwera rozsądnym minimum jest codzienne uruchamianie, a deduplikacja sprawia, że jest to tanie: każde uruchomienie przesyła tylko fragmenty, które zmieniły się od ostatniego razu. Dane, które zmieniają się szybko lub których utrata nawet za jeden dzień byłaby dotkliwa, mogą być kopiowane co kilka godzin przy użyciu tego samego harmonogramu. Częstotliwość to tylko połowa sukcesu; regularnie uruchamiaj również restic check i co miesiąc przeprowadzaj ćwiczenie przywracania, ponieważ harmonogram bez weryfikacji to złudne poczucie bezpieczeństwa.

Co się stanie, jeśli zgubię hasło do repozytorium restic?

Kopie zapasowe są niemożliwe do odzyskania. Szyfrowanie restic nie posiada tylnych furtek ani opcji resetowania, więc hasło jest tak samo ważne jak same kopie zapasowe. Przechowuj kopię w menedżerze haseł oraz w innym trwałym miejscu, które nie jest serwerem objętym kopią zapasową. Dopóki masz dostęp do repozytorium, restic key add pozwala zarejestrować drugie hasło dla tego samego repozytorium, co zapewnia zapasowy dostęp.