Zálohy na Cloudflare R2 přes restic
Mám rád zálohy, kterým nemusím rozumět, abych je obnovil. Restic je přesně takový nástroj: jeden binárka v Go, jeden šifrovaný repozitář, deduplikace, snapshoty, a S3-kompatibilní backend, který se dá hostovat prakticky kdekoli. Cloudflare R2 je v tomhle ohledu příjemný cíl – S3 API, žádné poplatky za egress, dostupné z čehokoliv, co umí mluvit přes HTTPS.
Tenhle zápis je obecný návod. Nepředpokládá konkrétní server ani strukturu dat – jen Linux box, který chce posílat svoje důležité věci někam, kde přežijí požár v serverovně.
Proč zrovna restic
Tři vlastnosti, kvůli kterým za tím stojí jít:
- Šifrování na straně klienta. Repozitář je AES-256 + Poly1305.
Server (R2, S3, B2, lokální disk, SFTP) nevidí obsah ani metadata
souborů. Klíč drží jen ten, kdo zná
RESTIC_PASSWORD. - Content-defined chunking. Restic data nerozseká po pevně dlouhých blocích, ale podle obsahu (rolling hash). Když vložíš do souboru jeden byte uprostřed, znova se nahraje jen pár chunků, ne celý soubor. V praxi to znamená, že druhý a další snapshot trvá vteřiny a zabere desítky kilobytů.
- Snapshoty místo verzí. Každé spuštění
backupje samostatný snapshot s časovým razítkem a tagem. Restore není o „obnov soubor X z verze 3″, ale o „namountuj snapshot z minulého úterý a vezmi si z něj, co potřebuješ.“
Co restic není: real-time replikace, journalovaný file system, ani náhrada za RAID. Je to backup, ne failover.
Proč R2
R2 je objektové úložiště od Cloudflare s S3-kompatibilním API. Hlavní důvody, proč ho zvážit pro zálohy:
- Nulový egress. Stahování dat zpátky nestojí nic. U AWS S3 platíš za každý gigabyt, který opustí region; u restoru terabajtových záloh to bolí.
- Cena za storage. Aktuálně řádově 0.015 USD za GB-měsíc, levnější než S3 Standard, srovnatelné s B2 Backblaze.
- S3 API. Restic ho umí out-of-the-box, žádný custom plugin.
Co je třeba si pohlídat: R2 nepoužívá virtual-hosted URLs (tj. bucket.endpoint), restic to ostatně ani nechce – spoléhá na
path-style (endpoint/bucket). U R2 to vychází přirozeně, endpoint
vypadá https://<account-id>.r2.cloudflarestorage.com a bucket se
připojuje za lomítko.
Příprava na straně R2
V Cloudflare dashboardu, sekce R2:
- Založ bucket. Jméno je globální v rámci tvého účtu, kratší je lepší.
- V sekci Manage R2 API Tokens vytvoř token typu User API Token s oprávněním Object Read & Write omezeným na konkrétní bucket. Token jde svázat s jediným bucketem – dělej to, omezený blast radius za to stojí.
- Po vytvoření dostaneš tři údaje: Access Key ID, Secret Access Key a endpoint URL. Secret se ukáže jenom jednou, ulož si ho hned.
Verzování ani lifecycle pravidla na úrovni R2 nepotřebuješ – retenci
si restic řeší sám přes forget.
Instalace restic
Na Debianu/Ubuntu:
sudo apt install restic
Verze v Debianu stable bývá o pár měsíců pozadu. Pokud chceš aktuální
release, stáhni binárku z github.com/restic/restic/releases a hoď ji do /usr/local/bin/. Restic je single static binary, žádné
runtime závislosti.
restic version
Konfigurace přes environment
Restic čte přihlašovací údaje a cestu k repozitáři z proměnných prostředí. Tahle čtveřice je všechno, co potřebuje:
export AWS_ACCESS_KEY_ID="<access-key-z-r2>"
export AWS_SECRET_ACCESS_KEY="<secret-z-r2>"
export RESTIC_REPOSITORY="s3:https://<account-id>.r2.cloudflarestorage.com/<bucket>"
export RESTIC_PASSWORD="<silne-heslo-na-sifrovani>"
Pár poznámek k téhle čtveřici:
AWS_*jsou jen názvy – restic používá AWS SDK, ale jde o credentials pro R2.RESTIC_REPOSITORYmá prefixs3:a pak plnou URL endpointu i s bucketem.RESTIC_PASSWORDjde nahraditRESTIC_PASSWORD_FILE(cesta k souboru s heslem) neboRESTIC_PASSWORD_COMMAND(libovolný příkaz, jehož stdout je heslo – typickypass,gopass,secret-tool, ap.). Pro automatizaci preferuj soubor s právy600.
Heslo k repozitáři si zapiš mimo server. Bez něj jsou data nečitelná i pro tebe. Hardware password manager, papírová záloha v šuplíku, šifrovaný USB stick u rodičů – cokoli, co přežije ztrátu serveru.
Inicializace repozitáře
S exportovanými proměnnými stačí:
restic init
Restic v bucketu vytvoří strukturu config, keys/, data/, index/, snapshots/, locks/. config je šifrovaný JSON
s parametry repozitáře, keys/ drží wrappované master klíče
(jeden per heslo – ano, repozitář může mít víc hesel).
Init udělej jen jednou. Při dalších voláních proti existujícímu repozitáři restic poznám, že je inicializovaný, a odmítne.
První záloha
Záloha adresáře:
restic backup /home /etc --tag system
Co se stane:
- Restic projde strom, načte soubory, rozseká je content-defined chunkingem, každý chunk zašifruje a nahraje, pokud ho repozitář ještě nemá.
- Vytvoří snapshot – malý objekt, který říká „v čase T na hostu H z cesty P měl strom tenhle obsah.“
- Vypíše souhrn: kolik souborů, kolik nových chunků, kolik bytů se nahrálo.
První záloha je vždy „drahá“ -- nahrává se prakticky všechno. Druhá a každá další jsou levné: nahrávají se jen rozdíly. Mám zkušenost, že denní inkrement domovského adresáře s pár gigabyty kódu, fotek a mailu se vejde do desítek megabytů.
Výluky
Skoro nikdy nechceš zálohovat všechno. Cache, build artefakty, dočasné soubory, virtuální prostředí – to všechno radši ne.
restic backup /home \
--exclude='**/node_modules' \
--exclude='**/.cache' \
--exclude='**/target' \
--exclude='**/__pycache__' \
--exclude-caches
Komfortnější je exclude file:
restic backup /home --exclude-file /etc/restic/excludes.txt
Kde soubor vypadá podobně jako .gitignore – jeden pattern na řádek,
komentáře #, negace !. Patterns používají filepath-style matching
(*, **, ?, [abc]). --exclude-caches přeskočí adresáře,
ve kterých je CACHEDIR.TAG – moderní cache to umí (Cargo, npm i jiné).
Tagy
restic backup /home --tag home --tag daily
Tagy se hodí pro forget (retence per-tag) a pro filtrování při snapshots a restore.
Snapshoty
restic snapshots
Vypíše seznam: ID, čas, host, paths, tagy. Filtruj přes --tag, --host, --path.
restic snapshots --tag daily --host myhost
Pro detaily konkrétního snapshotu:
restic ls <id> # výpis souborů ve snapshotu
restic diff <id1> <id2> # rozdíl mezi snapshoty
restic stats <id> # velikost a počty
Restore
Tři způsoby, jak se k datům dostat:
Klasický restore do adresáře:
restic restore latest --target /tmp/restore --path /home
latest vybere nejnovější snapshot, --path ho zúží na ten, který
zálohoval danou cestu (užitečné, když pod jedním repozitářem děláš
zálohy víc systémů).
Selektivní restore:
restic restore <id> --target /tmp/restore --include '/home/jirka/.gnupg'
FUSE mount – nejpohodlnější pro jednorázové dohledávky:
mkdir /mnt/restic
restic mount /mnt/restic
V /mnt/restic se objeví strom snapshots/<host>/<datum>/, v něm
přesně to, co bylo zálohované. Procházíš to ls, kopíruješ cp,
hledáš grep. Při ukončení (Ctrl+C) se filesystem odpojí.
Mount je read-only, takže neexistuje cesta, jak si při restoru rozbít repozitář.
Retence – forget a prune
Záloha bez retence po čase přeroste. Restic řeší retenci dvoufázově:
forgetodstraní referenci na snapshot z indexu. Snapshot zmizí z výpisu, ale jeho data jsou pořád v repozitáři (sdílí je jiné snapshoty).pruneprochází repozitář a maže chunky, na které už nikdo neukazuje.
Typická politika – 7 denních, 4 týdenní, 12 měsíčních a 3 roční:
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 12 \
--keep-yearly 3 \
--prune
Co dělá --keep-daily 7: vezme 7 nejnovějších dní, ve kterých byl
snapshot, a z každého dne nechá ten nejnovější. Ne posledních 7 dní
v kalendáři – 7 dní s daty. Kalendáře (týden, měsíc, rok) restic
počítá podle skutečných hranic (týden = pondělí--neděle), takže
„měsíční“ snapshot je první ze začátku měsíce.
--prune zařadí prune do stejného běhu. U velkých repozitářů
(stovky GB) trvá prune dlouho a generuje hodně requestů – v takovém
případě je rozumné dělat forget často, prune jednou týdně:
# denně
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12
# v neděli
restic prune
Před produkčním nasazením politiky vyzkoušej --dry-run – ukáže,
co by zmizelo, bez reálné akce.
Kontrola integrity
R2 (ani žádné jiné cloud storage) nepřidává záruku, že to, co jsi nahrál, je bit-perfektně to, co se ti později vrátí. Restic má proto vestavěnou verifikaci.
Levná kontrola (jen metadata a struktura):
restic check
Plná kontrola (stáhne všechna data a přepočítá hashe – drahé):
restic check --read-data
Pro velké repozitáře se hodí postupná verifikace – v každém běhu přečíst jen kus dat:
restic check --read-data-subset=10%
Za deset běhů jsi prošel celé úložiště. Tohle je rozumný kompromis mezi důvěrou a náklady – u R2 jsou náklady jen čas a CPU, egress je zdarma.
Automatizace přes systemd
Restic není daemon – spouští se externím schedulerem. Cron funguje, ale systemd timer dává lepší kontrolu nad výstupem a chybami.
/etc/systemd/system/restic-backup.service:
[Unit]
Description=Restic backup to R2
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env
ExecStart=/usr/local/bin/restic backup /home /etc \
--exclude-file /etc/restic/excludes.txt \
--tag daily
ExecStartPost=/usr/local/bin/restic forget \
--keep-daily 7 --keep-weekly 4 --keep-monthly 12 \
--tag daily
/etc/systemd/system/restic-backup.timer:
[Unit]
Description=Daily restic backup
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
/etc/restic/env:
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
RESTIC_REPOSITORY=s3:https://<account-id>.r2.cloudflarestorage.com/<bucket>
RESTIC_PASSWORD_FILE=/etc/restic/password
Soubor env i password chmodni na 600, ownership root:root.
Aktivace:
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer
systemctl list-timers restic-backup.timer
RandomizedDelaySec rozhází běhy v čase – užitečné, když máš víc
strojů a nechceš, aby všechny narazily na R2 ve 03:00:00 současně. Persistent=true zajistí, že pokud byl stroj při plánovaném čase
vypnutý, restic doběhne po startu.
Co když je server pryč
Tohle je test, který stojí za to udělat před tím, než ho budeš potřebovat. Na čerstvém stroji:
sudo apt install restic
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export RESTIC_REPOSITORY=s3:https://<account-id>.r2.cloudflarestorage.com/<bucket>
export RESTIC_PASSWORD=...
restic snapshots
restic restore latest --target /restore
Pokud snapshots ukáže seznam a restore latest doběhne, máš funkční
disaster recovery. Pokud něco z toho nejede, lepší zjistit teď.
Co si dát do popisku scénáře:
- Heslo k repozitáři není v repozitáři. Musíš si ho pamatovat, nebo mít offline.
- API credentials k R2 můžeš v Cloudflare regenerovat – ale jen z účtu, do kterého se dostaneš. Backup-of-backup pro Cloudflare přihlašování (2FA recovery codes, atd.) je samostatné téma.
- Disk space na restore – nezkoušej restore terabajtu na 50GB systémový disk.
Co tady není
Multi-host repozitáře (jeden bucket, víc strojů – jde to, ale chce to
opatrnost s --host a tagy), repository copy (restic copy pro
zrcadlení do druhého úložiště – belt and suspenders), key management
(více hesel k jednomu repo), append-only mód pro ransomware-resistant
zálohy (přes B2 jde lépe než přes R2). To všechno stojí za vlastní
zápis. Tady je základ – jednoduchý strom, jeden bucket, jeden host,
plánovač v systemd. To dostane většinu provozu.
Restic má jednu velmi cennou vlastnost: skoro nikdy tě nepřekvapí. Když se ho budeš ptát hloupě, řekne ti to. Když mu zadáš nesmysl, nepustí ho. To je u zálohovacího nástroje vlastnost, kterou si nelze přeplatit.