Samstag, 06:42 Uhr, Monitoring-Mail: „Backup fehlgeschlagen." Ich öffne das Dashboard, sehe die rote Zeile, starte den Job neu und vergesse das Ganze, bis die nächste Mail kommt. So lief das jahrelang. Das Backup lief, der Zähler stand auf OK, und irgendwo in einem S3-Bucket lag eine Kopie meines Servers. Ob ich sie je zurück auf eine Maschine bekäme, wusste ich nicht. Bis zu dem Sonntag, an dem ich es ausprobiert habe.
Das Ergebnis war ernüchternd und beruhigend zugleich: Der komplette Restore-Test dauerte 38 Minuten. 4,2 TB Rohdaten als sieben tägliche Snapshots, dedupliziert auf ein 680-GB-Repo, verschlüsselt in S3, zurück auf einem frischen Server. Ohne Drama. Dieser Artikel zeigt das Setup, die Befehle, die ich wirklich benutze, und warum jeder Integritätscheck bei mir durch den Hash-Generator läuft.
Der Moment, in dem „das Backup ist irgendwo" nicht mehr reichte
Vor ein paar Jahren ist auf einem meiner Server die Systemplatte gestorben. So ein Defekt, der sich mit einem Klick ankündigt und dann mit einem leisen Klacken endet. Ich hatte ein rsync-Skript, das nachts lief, und eine externe Platte im Schrank. Klingt nach einem Plan. Bis ich nach dem Plattenwechsel vor dem ersten rsync stand und merkte: Ich wusste nicht, ob die Kopie vollständig war, ob sie aktuell war und ob das Skript überhaupt je fehlerfrei durchgelaufen war. Es gab keine Logs, keine Prüfsummen, keine Wiederholbarkeit. Nur „irgendwo" eine Kopie.
Die Daten kamen damals heil zurück, das war Glück, kein System. Danach habe ich drei Regeln aufgestellt, die bis heute gelten: Backups müssen verschlüsselt sein, bevor sie das Haus verlassen. Backups müssen sich automatisch verifizieren lassen. Und mindestens einmal im Quartal wird ein Restore auf einer frischen Maschine durchgespielt, mit Stoppuhr. Restic war das Werkzeug, das alle drei Regeln abdeckt, ohne dass ich dafür eine zweite Maschine oder ein Backup-Produkt mit eigener Verwaltungsoberfläche brauche.
Das Setup: Ein Server, 4,2 TB, ein S3-Bucket
Es ist ein einzelner Server, kein Cluster. Zwei Datenverzeichnisse, zusammen 4,2 TB Rohdaten: Webserver-Dateien, Datenbank-Dumps, Verzeichnisse mit Nutzer-Uploads. Dazu ein S3-Bucket bei einem europäischen Anbieter mit Server-Side Encryption und Object Lock, damit auch ein kompromittierter Admin-Account die Snapshots nicht stillschweigend löschen kann.
Das Repo wird einmal angelegt, der Rest passiert automatisch:
export RESTIC_REPOSITORY=s3:s3.eu-central-1.amazonaws.com/mein-bucket/restic
export RESTIC_PASSWORD_FILE=/etc/restic/passphrase
restic init
restic init legt die Repo-Struktur an, erzeugt die Schlüssel und schreibt die Konfiguration. Der Inhalt des Repos ist ohne Passphrase nur Rauschen. Das Passwort liegt in einer Datei mit 600er-Rechten, root-only, und zusätzlich in einem Tresor, damit ich es nicht verliere. Ein verlorenes Passwort ist bei restic ein verlorenes Backup, das schreibt einem keiner auf die Verpackung.
Der tägliche Lauf
Ein Cronjob um 22:00 Uhr, mehr nicht:
0 22 * * * restic backup /srv/data --exclude /srv/data/cache --tag daily
Der Lauf liest die Verzeichnisse, zerlegt alles in Chunks, vergleicht mit dem, was schon im Repo liegt, und lädt nur Neues hoch. Nach dem Lauf wird aufgeräumt, damit das Repo nicht unendlich wächst:
restic forget --keep-daily 7 --keep-weekly 4 --prune
Sieben tägliche Snapshots bleiben, dazu vier wöchentliche. Genau die sieben Tage, die ich in der Infografik oben durchgerechnet habe. --prune entfernt Chunks, die kein Snapshot mehr referenziert, das läuft einmal pro Woche mit, nicht jeden Abend.
Was restic beim Backup wirklich macht
Das Herzstück ist das Chunking mit anschließender Deduplizierung. Restic zerlegt Dateien anhand ihres Inhalts in variable Blöcke, etwa 8 MB groß. Gleicher Inhalt an anderer Stelle oder in einer anderen Datei erzeugt denselben Chunk-Hash, und derselbe Chunk wird nur einmal gespeichert. Ein Snapshot ist dann im Kern ein Baum aus Chunk-Verweisen, nicht eine Kopie der Daten.
Jeder Chunk wird vor dem Hochladen mit AES-256 verschlüsselt. Im S3-Bucket liegen keine Dateien und keine Verzeichnisnamen, nur undurchsichtige Pakete. Wer den Bucket liest, sieht nichts Verwertbares, wer das Repo mountet, sieht nichts ohne Passphrase.
Die Zahlen aus meinem Setup nach einer Woche Laufzeit:
- 4,2 TB Rohdaten über sieben Snapshots
- 680 GB Repo-Größe nach Deduplizierung und Kompression, Faktor ungefähr 6,2
- Ein durchschnittlicher Abendlauf dauert einige Minuten, je nachdem, wie viel sich geändert hat
Was gelaufen ist, prüfe ich mit einem Blick:
restic snapshots
Sieben Zeilen, jede mit Zeitstempel, Hostname, Pfaden und Tag. Fehlt eine Zeile, weil der Job abgebrochen wurde, sehe ich es sofort, und die Monitoring-Mail hat mich vorher schon gewarnt.
Der Restore-Test: 38 Minuten bis zur ersten Zeile
Sonntag, 09:00 Uhr. Frische Maschine, gleiche Hardware-Klasse, gleiche Partitionierung. Ziel: den letzten Snapshot so zurückholen, wie ein Ernstfall es verlangt. Kein gemütliches Ausprobieren, sondern die Frage: Wie lange dauert es, bis dieser Server wieder produktiv ist?
restic restore latest --target /srv/restore-test
Dann lief die Stoppuhr. 31 Minuten hat allein das Wiederherstellen gedauert: Download aus S3, Entschlüsselung, Entpacken der Chunks in die Zielverzeichnisse. Danach sieben Minuten Verifikation. Ich habe die Dateianzahl verglichen, die Größen geprüft und stichprobenartig Prüfsummen gezogen:
find /srv/restore-test -type f | wc -l
sha256sum /srv/restore-test/dumps/mysql-2026-09-13.sql
38 Minuten gesamt, bis die erste Zeile aus der wiederhergestellten Datenbank kam. Für einen Ein-Server-Betrieb ist das die Antwort auf die Frage, die jeder Chef irgendwann stellt: Wie lange sind wir down? Antwort: kürzer als ein durchschnittlicher Montagmorgen.
Wichtig ist mir der Unterschied zwischen dem, was dieser Test geprüft hat, und dem, was er nicht geprüft hat. Der Test beweist, dass der letzte Snapshot vollständig lesbar und wiederherstellbar ist. Er beweist nicht, dass die Daten inhaltlich korrekt sind. Dafür gibt es die Prüfsummen.
Warum jeder Check durch den Hash-Generator läuft
Hier kommt das Werkzeug ins Spiel, das auf dieser Seite ohnehin liegt: der Hash-Generator. restic check prüft die Integrität des Repos, also ob die Chunks unversehrt und referenzierbar sind. Was es nicht prüft, ist, ob der Inhalt eines Chunks dem entspricht, was vor zwei Wochen aus der Datenbank exportiert wurde. Ein logischer Fehler im Export, ein stilles Datenproblem in der Quelle: Das Repo bleibt davon unberührt und sieht trotzdem gesund aus.
Deshalb läuft bei mir jede Sicherung von kritischen Dateien durch zwei Stellen: Vor dem Backup wird eine SHA-256-Summe berechnet und in einem Manifest gespeichert. Nach dem Restore-Test wird dieselbe Datei erneut gehasht und mit dem Manifest verglichen. Genau dafür nehme ich den Hash-Generator auf dieser Seite: Datei hochladen, Hash ablesen, mit dem Wert aus dem Manifest vergleichen. Zwei unabhängige Implementierungen müssen dasselbe Ergebnis liefern, bevor ich eine Wiederherstellung für abgeschlossen erkläre.
Im Alltag heißt das konkret: Die Datenbank-Dumps, die jeden Morgen entstehen, haben eine feste Namenskonvention mit Datum. Das Manifest speichert Hash, Dateiname und Größe. Beim Restore-Test vergleiche ich eine Handvoll dieser Einträge. Passt der Hash, ist der Snapshot nicht nur lesbar, sondern auch inhaltlich richtig. Das ist der Unterschied zwischen „wiederhergestellt" und „wiederhergestellt und geprüft".
restic check: Die wöchentliche Inventur
Ein Backup, das nie geprüft wird, ist eine Meinung, kein Backup. Bei mir läuft der Check wöchentlich, mit einer Besonderheit: --read-data-subset liest nicht alles auf einmal, sondern nur einen Prozentsatz der Daten. Über zehn Wochen ist so jeder Chunk mindestens einmal komplett vom S3-Bucket gelesen und verifiziert worden, ohne dass ein einzelner Lauf die Leitung über Stunden blockiert.
restic check --read-data-subset 10%
Das deckt die Integrität im Repo ab. Einmal im Quartal, zusammen mit dem Restore-Test, läuft der volle Lauf: restic check --read-data. Der liest wirklich alles, 680 GB aus S3, und dauert entsprechend. Danach weiß ich, dass das Repo von vorne bis hinten gelesen werden kann. In Kombination mit dem Hash-Abgleich aus dem vorherigen Abschnitt sind das zwei unabhängige Prüfungen: eine auf Repo-Ebene, eine auf Datei-Ebene.
Was ein off-site Restore wirklich kostet
Der Restore-Test oben lief direkt aus S3 heraus, und 31 Minuten fühlten sich fast gemütlich an. Der Ernstfall sieht anders aus: 680 GB aus einem S3-Bucket über die normale Leitung zurückholen. Bei 100 Mbit/s sind das rechnerisch über 15 Stunden, bei 1 Gbit/s immer noch über anderthalb Stunden. Genau dafür gibt es auf dieser Seite den Download-Zeit-Rechner: Größe und Anbindung eintragen, und man sieht sofort, ob der Wiederanlauf am Montag in einer Stunde oder in zwei Tagen liegt.
Diese Zahl ändert, wie ich Retention plane. Wenn ein Restore aus S3 über die Leitung dauert, ist ein zusätzlicher lokaler Snapshots-Pool mehr wert als ein weiterer Monat im Bucket. Für den schnellen Weg zurück gibt es den lokalen Snapshot, für den sauberen Weg die off-site Kopie. Beide müssen funktionieren, aber nur eine muss schnell sein.
Fazit
Seit dem ersten Restore-Test nenne ich mein Backup nicht mehr „das Backup ist irgendwo". Es ist ein Repo mit einer bekannten Größe, einem bekannten Passwort, einem bekannten Prüfplan und einer bekannten Wiederherstellungszeit. 38 Minuten. Das ist der Unterschied zwischen einem Backup, das man hat, und einem Backup, an das man glaubt.
Die drei Regeln, die übrig bleiben: verschlüsseln, bevor es das Haus verlässt, wöchentlich prüfen, vierteljährlich restaurieren. Restic macht den ersten Teil, der Kalender den Rest.
0 3 * * 0 restic check --read-data-subset 10%