Zum Inhalt springen
Serverküche
Suche

Die Suche wird geladen … (nur in der veröffentlichten Seite verfügbar).

Sicherheit Schwierigkeit: Fortgeschritten

Restic-Backups einrichten: verschlüsselt und off-site

Off-Site-Backups mit Restic: verschlüsselt einrichten, Snapshots wiederherstellen, mit Retention aufräumen und per systemd-Timer automatisieren.

· 11 Min. Lesezeit ·Dauer: ca. 45 Minuten
Inhaltsverzeichnis

Ein Snapshot beim Anbieter ist kein Backup: Er liegt auf derselben Infrastruktur und ist mit weg, wenn dein Account gesperrt wird, das Rechenzentrum brennt oder du versehentlich das falsche Projekt löschst. Restic macht daraus ein echtes Backup – verschlüsselt, dedupliziert und an einem Ort außerhalb deines Servers.

Was bauen wir?

Am Ende sichert Restic deine wichtigen Daten – App-Volumes, Konfigurationen, Datenbank-Dumps – Ende-zu-Ende-verschlüsselt und dedupliziert in ein Repository, idealerweise off-site (zweiter Server oder Storage). Du kannst jederzeit einzelne Dateien oder ganze Snapshots wiederherstellen, alte Backups nach einer Aufbewahrungsregel automatisch ausdünnen und die Integrität prüfen. Zum Schluss läuft alles automatisch per systemd-Timer und meldet sich, wenn ein Lauf ausbleibt.

Getestet mit Restic 0.18 (die Version aus den Debian-13-Paketquellen); upstream gibt es bereits 0.19.x – wie du aktualisierst, steht in Schritt 1. Restic verschlüsselt immer – es gibt kein unverschlüsseltes Repository.

Snapshot ≠ Backup

Der Snapshot im Anbieter-Panel ist ein bequemes „Zurückspulen" – aber er liegt auf derselben Infrastruktur und unter demselben Account. Fällt der Anbieter, das Rechenzentrum oder dein Zugang aus, ist der Snapshot mit weg. Ein echtes Backup liegt außerhalb (anderer Anbieter/Standort), ist verschlüsselt und du kannst es unabhängig wiederherstellen. Genau das ist Restics Aufgabe – der Snapshot bleibt das schnelle Netz für kleine Missgeschicke.

Voraussetzungen

  • Ein Server (Debian 13) mit den Daten, die du sichern willst – z. B. die Volumes und Compose-Dateien deiner Docker-Apps.
  • Ein Off-Site-Ziel für die Backups. Restic spricht u. a.:
    • SFTP – ein zweiter Server oder eine Storage-Box (am einfachsten zu starten),
    • S3-kompatibel – z. B. ein Object-Storage-Bucket,
    • rclone – als Brücke zu Backblaze B2, Google Drive und Dutzenden weiteren.
  • Grundvertrautheit mit der Shell.
🍳 Empfehlung Anzeige

VPS 1000 G12

4 vCore · 8 GB RAM · 256 GB NVMe

ab 10,36 €/Monat

Ein kleiner zweiter VPS an einem anderen Standort ist ein günstiges, dediziertes Backup-Ziel per SFTP.

Zu netcup →

💶 5 € Gutschein für netcup-Neukunden:36nc17844976032 (nur Neukunden, keine Domains)

Schritt für Schritt

Schritt 1: Restic installieren

Restic liegt in den Paketquellen und wird so mit dem System aktualisiert:

Terminal
sudo apt update
sudo apt install -y restic

Prüfe die Version:

Terminal
restic version
Ausgabe
restic 0.18.0 compiled with go1.24.4 on linux/amd64

Neuere Version bei Bedarf

Upstream ist Restic teils voraus (aktuell 0.19.x). Brauchst du eine neuere Funktion, lade das offizielle Binary von der Restic-Release-Seite herunter und lege es nach /usr/local/bin (das hat Vorrang vor /usr/bin). Der eingebaute Befehl restic self-update funktioniert mit der Debian-Paketversion nicht – das Paket ist ohne diese Funktion gebaut (unknown command "self-update"). Für die meisten reicht die Paketversion völlig.

Schritt 2: Das verschlüsselte Repository anlegen

Ein Restic-Repository ist der verschlüsselte Speicherort deiner Backups. Es wird mit einem Passwort geschützt – und dieses Passwort gehört nicht in ein Skript und nicht neben das Repository. Lege es in eine Datei, die nur root lesen darf:

Terminal
sudo install -d -m 700 /etc/restic
openssl rand -base64 32 | sudo tee /etc/restic/password > /dev/null
sudo chmod 600 /etc/restic/password

Der openssl-Befehl erzeugt ein langes Zufallspasswort und legt es unter /etc/restic/password ab (der install-Befehl davor erstellt das Verzeichnis, chmod danach schützt die Datei). Sag Restic über Umgebungsvariablen, wo das Repository liegt und wo das Passwort steht – hier zunächst ein Off-Site-Ziel per SFTP:

Terminal
export RESTIC_REPOSITORY="sftp:BACKUP_BENUTZER@DEIN_BACKUP_HOST:/backups/DEIN_SERVER"
export RESTIC_PASSWORD_FILE="/etc/restic/password"

Ersetze BACKUP_BENUTZER, DEIN_BACKUP_HOST und den Pfad durch dein echtes Ziel. Willst du erst lokal üben, nimm stattdessen einen Ordner: export RESTIC_REPOSITORY="/srv/restic-repo". Die Befehle danach sind identisch – nur die Repository-Adresse unterscheidet sich.

Andere Off-Site-Ziele nutzt du über dieselbe Variable, nur mit anderem Präfix:

  • S3-kompatibel: s3:https://ENDPUNKT/BUCKET – dazu die Zugangsdaten als AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY in der Umgebung (bzw. in der Environment-Datei aus Schritt 7).
  • rclone: rclone:REMOTE:pfad – die Brücke zu Backblaze B2, Google Drive und vielen weiteren, sobald du das rclone-Remote einmal eingerichtet hast.

Egal welches Backend: Verschlüsselung, Deduplizierung und alle folgenden Befehle bleiben gleich.

Jetzt das Repository initialisieren (die Beispiel-Ausgabe zeigt das lokale Übungs-Repository – beim SFTP-Ziel steht dort entsprechend deine sftp:-Adresse):

Terminal
restic init
Ausgabe
created restic repository 9d28ae7601 at /srv/restic-repo

Please note that knowledge of your password is required to access
the repository. Losing your password means that your data is
irrecoverably lost.

Passwort verloren = Daten verloren

Es gibt keine Hintertür. Ohne das Repository-Passwort sind deine Backups unwiederbringlich verschlüsselt. Sichere den Inhalt von /etc/restic/password zusätzlich in einem Passwortmanager – getrennt vom Server, sonst nützt es dir bei einem Serververlust nichts.

Schritt 3: Das erste Backup

Sichere das Verzeichnis mit deinen Daten. Der --tag hilft später beim Filtern:

Terminal
restic backup /root/backup-demo --tag demo
Ausgabe
no parent snapshot found, will read all files

Files:           3 new,     0 changed,     0 unmodified
Dirs:            2 new,     0 changed,     0 unmodified
Added to the repository: 2.002 MiB (2.001 MiB stored)

processed 3 files, 2.000 MiB in 0:00
snapshot 210e2933 saved

Beim zweiten Lauf zeigt sich Restics Stärke: Es sichert nur die Änderungen (Deduplizierung). Ändert sich eine Datei und du sicherst erneut:

Ausgabe
using parent snapshot 210e2933

Files:           0 new,     1 changed,     2 unmodified
Dirs:            0 new,     2 changed,     0 unmodified
Added to the repository: 1.829 KiB (1.116 KiB stored)

processed 3 files, 2.000 MiB in 0:00
snapshot 8d059af6 saved

Statt wieder 2 MiB landen nur 1,1 KiB im Repository – nur der geänderte Teil.

Was gehört ins Backup? Für Docker-Apps sind das drei Dinge – Rezept, Nutzdaten, DB:

  • Compose-Dateien (dein „Rezept") und .env: klein, aber unverzichtbar, um den Stack wieder aufzubauen.
  • Bind-Mounts (./data:/…) liegen direkt im Projektordner – die sicherst du einfach mit. Named Volumes findest du unter /var/lib/docker/volumes/<name>/_data; nimm den Pfad mit auf.
  • Datenbanken niemals als laufende Datei sichern – ein Backup mitten im Schreibvorgang ist womöglich unbrauchbar. Erzeuge stattdessen einen konsistenten Dump (pg_dump/mariadb-dump) und sichere den (siehe Schritt 7).

Unnötiges schließt du aus:

Terminal
restic backup /opt --tag apps --exclude='*.log' --exclude='**/cache/**'

Schritt 4: Wiederherstellen

Ein Backup ist nur so gut wie sein Restore. Liste zunächst die Snapshots:

Terminal
restic snapshots
Ausgabe
ID        Time                 Host                  Tags        Paths              Size
---------------------------------------------------------------------------------------------
210e2933  2026-08-20 01:35:39  v2200000000000000000  demo        /root/backup-demo  2.000 MiB
8d059af6  2026-08-20 01:35:39  v2200000000000000000  demo        /root/backup-demo  2.000 MiB
---------------------------------------------------------------------------------------------
2 snapshots

Stelle einen kompletten Snapshot in ein Zielverzeichnis wieder her (nutze latest für den neuesten oder eine konkrete ID):

Terminal
restic restore latest --target /root/restore-test
Ausgabe
restoring snapshot 8d059af6 of [/root/backup-demo] at 2026-08-20 01:35:39.79530411 +0200 CEST by root@v2200000000000000000 to /root/restore-test
Summary: Restored 5 files/dirs (2.000 MiB) in 0:00

Brauchst du nur eine Datei, gibt es zwei Wege – gezielt diesen Pfad wiederherstellen:

Terminal
restic restore latest --target /tmp/wiederher --include /root/backup-demo/config.yaml

… oder die Datei direkt auf die Standardausgabe streamen, ganz ohne Umweg:

Terminal
restic dump latest /root/backup-demo/config.yaml > /tmp/config.yaml

Zum Stöbern hängst du das Repository sogar als Dateisystem ein (restic mount /mnt/backup, benötigt FUSE) und kopierst im Dateimanager heraus, was du brauchst – praktisch, wenn du nicht mehr weißt, in welchem Snapshot die gesuchte Version steckt.

Schritt 5: Die Integrität prüfen

check verifiziert, dass die Struktur des Repositorys intakt ist:

Terminal
restic check
Ausgabe
using temporary cache in /tmp/restic-check-cache-175944302
create exclusive lock for repository
load indexes
check all packs
check snapshots, trees and blobs
[0:00] 100.00%  2 / 2 snapshots
no errors were found

Die ersten beiden Zeilen sind normal: check legt sich einen Wegwerf-Cache an und sperrt das Repository, damit während der Prüfung kein zweiter Lauf dazwischenfunkt.

Das prüft die Metadaten, aber nicht die eigentlichen Daten. Lies deshalb regelmäßig einen Teil der echten Daten mit – z. B. 10 % pro Lauf, über Wochen also alles:

Terminal
restic check --read-data-subset=10%

Schritt 6: Aufräumen mit einer Aufbewahrungsregel

Ohne Aufräumen wächst das Repository ewig. forget wendet eine Retention-Policy an, --prune gibt den Speicher der entfernten Snapshots frei:

Terminal
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
Ausgabe
Applying Policy: keep 7 daily, 4 weekly, 6 monthly snapshots
keep 2 snapshots:
ID        Time                 Host                  Tags        Reasons                  Paths              Size
----------------------------------------------------------------------------------------------------------------------
210e2933  2026-08-20 01:35:39  v2200000000000000000  demo        oldest daily snapshot    /root/backup-demo  2.000 MiB
                                                                 oldest weekly snapshot
                                                                 oldest monthly snapshot
8d059af6  2026-08-20 01:35:39  v2200000000000000000  demo        daily snapshot           /root/backup-demo  2.000 MiB
                                                                 weekly snapshot
                                                                 monthly snapshot
----------------------------------------------------------------------------------------------------------------------
2 snapshots

Die Spalte Reasons ist der interessante Teil: Sie sagt dir für jeden behaltenen Snapshot, welche Regel ihn gerettet hat. Hier fällt noch nichts weg – beide Snapshots sind vom selben Tag und damit „daily", „weekly" und „monthly" zugleich.

Das behält die letzten 7 täglichen, 4 wöchentlichen und 6 monatlichen Snapshots – ein guter Standard. Die Stufen greifen ineinander: feine Auflösung für die jüngste Vergangenheit (jeden Tag einer), gröber je weiter zurück (einer pro Woche, dann einer pro Monat). So kommst du im Zweifel nah an den gewünschten Stand heran, ohne dass das Repository unbegrenzt wächst. Ältere Snapshots fallen automatisch weg. --prune ist der aufwändige Teil (es packt Daten um); bei großen Repositories lässt man es oft nur ein- bis zweimal pro Woche laufen, nicht bei jedem Backup.

Schritt 7: Alles automatisieren (systemd-Timer)

Ein Backup, das du von Hand starten musst, vergisst du. Lege die Zugangsdaten als Environment-Datei ab (damit der Dienst sie kennt):

Terminal
# /etc/restic/restic.env
RESTIC_REPOSITORY=sftp:BACKUP_BENUTZER@DEIN_BACKUP_HOST:/backups/DEIN_SERVER
RESTIC_PASSWORD_FILE=/etc/restic/password

Dann ein Wrapper-Skript /usr/local/bin/restic-backup.sh – es dumpt zuerst die Datenbank (Beispiel PostgreSQL), sichert, räumt auf und meldet am Ende Erfolg an Uptime Kuma (der Push-Monitor als „Dead man’s switch"):

Terminal
#!/usr/bin/env bash
set -euo pipefail
# 0) Ziel-Verzeichnis für den Dump sicherstellen (sonst bricht der erste Lauf ab)
mkdir -p /opt/dumps
# 1) Datenbank konsistent dumpen (nie die laufende DB-Datei sichern)
docker exec DEIN_DB_CONTAINER pg_dumpall -U postgres > /opt/dumps/db.sql
# 2) Backup
restic backup /opt/apps /opt/dumps --tag auto
# 3) Aufräumen (Retention)
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
# 4) Erfolg an Uptime Kuma melden
curl -fsS "https://status.DEINE_DOMAIN/api/push/DEIN_TOKEN?status=up&msg=restic+OK" > /dev/null
Terminal
sudo chmod 700 /usr/local/bin/restic-backup.sh

Der Dienst lädt die Environment-Datei und führt das Skript aus – /etc/systemd/system/restic-backup.service:

INI
[Service]
Type=oneshot
EnvironmentFile=/etc/restic/restic.env
ExecStart=/usr/local/bin/restic-backup.sh

Und der Timer /etc/systemd/system/restic-backup.timer startet ihn täglich nachts:

INI
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

Persistent=true holt einen verpassten Lauf (z. B. weil der Server nachts aus war) beim nächsten Start nach. Aktivieren:

Terminal
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timer

Prüfe, wann der nächste Lauf ansteht:

Terminal
systemctl list-timers restic-backup.timer
Ausgabe
NEXT                          LEFT LAST PASSED UNIT                ACTIVATES
Thu 2026-08-20 02:30:00 CEST 53min -         - restic-backup.timer restic-backup.service

1 timers listed.

LAST/PASSED sind vor dem ersten Lauf leer. Willst du nicht bis nachts warten, starte den Dienst einmal von Hand mit sudo systemctl start restic-backup.service und sieh dir das Ergebnis mit journalctl -u restic-backup.service an.

Backup-Zeit nicht mit dem automatischen Reboot kollidieren lassen

Läuft auf dem Server ein automatischer Neustart durch unattended-upgrades (im dortigen Beispiel 04:00), muss das Backup vorher durch sein. Wird der laufende Backup-Lauf (restic backup bzw. das anschließende restic forget --prune) mitten im Betrieb vom Reboot abgeschnitten, bleibt eine stale Lock im Repository zurück (repository is already locked, siehe unten). Deshalb startet der Timer hier um 02:30 – genug Abstand für ein größeres Backup samt Aufräumen. Passt du eine der beiden Zeiten an, halte den Abstand bewusst groß.

Schritt 8: Den Ernstfall einmal proben

Ein Backup, das du nie zurückgespielt hast, ist nur eine Hoffnung. Spiele deshalb einmal bewusst einen kompletten Restore durch – idealerweise auf einem anderen oder frisch aufgesetzten Server, damit du auch die Zugangsdaten (Repository-Adresse und Passwort) unter realen Bedingungen brauchst:

Terminal
export RESTIC_REPOSITORY="sftp:BACKUP_BENUTZER@DEIN_BACKUP_HOST:/backups/DEIN_SERVER"
export RESTIC_PASSWORD_FILE="/etc/restic/password"
restic snapshots
restic restore latest --target /tmp/dr-test

Vergleiche danach Stichproben mit dem Original (diff, Datei-Hashes) und fahre die App aus den wiederhergestellten Daten testweise hoch. Erst wenn das klappt, weißt du, dass dein Backup im Ernstfall trägt – und dass du dich an den Ablauf erinnerst, wenn es wirklich darauf ankommt.

Wenn es nicht funktioniert

subprocess ssh: Host key verification failed beim SFTP-Ziel. Restic kann den SSH-Hostkey des Backup-Servers nicht bestätigen, weil er noch nicht bekannt ist. Verbinde dich einmal manuell (ssh BACKUP_BENUTZER@DEIN_BACKUP_HOST) und bestätige den Fingerprint – oder hinterlege ihn mit ssh-keyscan DEIN_BACKUP_HOST >> ~/.ssh/known_hosts. Danach läuft Restic durch.

wrong password oder repository does not exist. RESTIC_REPOSITORY oder RESTIC_PASSWORD_FILE ist nicht gesetzt oder zeigt ins Leere – im systemd-Dienst also die EnvironmentFile prüfen. Ein per Hand gesetztes export gilt nur in der aktuellen Shell.

repository is already locked. Ein abgebrochener Lauf hat eine Sperre hinterlassen. Prüfe, dass wirklich kein Backup mehr läuft, dann restic unlock. Niemals blind entsperren, während parallel ein Lauf aktiv ist.

Das Backup wird riesig / sichert Unsinn. Grenze mit --exclude/--exclude-file ein (Caches, Logs, temporäre Dateien) und nutze --one-file-system, damit Restic nicht in gemountete Fremd-Dateisysteme abtaucht.

prune dauert ewig oder wurde abgebrochen. Kein Grund zur Panik – prune ist wiederaufnehmbar und das Repository bleibt gültig. Starte es erneut und lass anschließend einmal restic check laufen. Trenne --prune bei großen Repos vom täglichen Backup (siehe Schritt 6).

Der Timer läuft, aber in Uptime Kuma kommt nie eine Erfolgsmeldung. Sieh dir den letzten Lauf mit journalctl -u restic-backup.service an. Meist bricht das Skript vor dem curl-Aufruf ab (z. B. der DB-Dump schlug fehl) – dank set -euo pipefail stoppt es dann sauber, statt ein kaputtes Backup als Erfolg zu melden. Der ausbleibende Push ist also kein Bug, sondern genau das Alarmsignal, das du haben willst.

Wartung & Backups

  • Restores regelmäßig testen – das ist der wichtigste Punkt überhaupt. Ein Backup, das du nie zurückgespielt hast, ist kein Backup, sondern eine Hoffnung. Plane monatlich einen Test-Restore in ein leeres Verzeichnis ein.
  • 3-2-1-Regel: mindestens 3 Kopien, auf 2 verschiedenen Medien, davon 1 off-site. Restic deckt das Off-Site-Stück ab – „off-site" heißt aber wirklich ein anderer Anbieter/Standort, nicht dasselbe Rechenzentrum.
  • Backups überwachen: Ohne Monitoring merkst du ein totes Backup erst im Ernstfall. Der Push-Aufruf aus Schritt 7 an Uptime Kuma schlägt Alarm, wenn ein Lauf ausbleibt.
  • Integrität prüfen: restic check --read-data-subset regelmäßig laufen lassen, damit stiller Bit-Rot auffällt, bevor du die Daten brauchst.
  • Passwort-/Schlüssel-Management: Das Repository-Passwort getrennt vom Server aufbewahren. Für einzelne Clients kannst du mit restic key add zusätzliche Passwörter vergeben, ohne das Haupt-Passwort zu teilen.

Zuletzt aktualisiert: 19.08.2026

Feedback per E-Mail: feedback@serverkueche.de

Wie geht's weiter?

Forgejo: der eigene Git-Server hinter Traefik
Anwendungen Fortgeschritten

Forgejo: der eigene Git-Server hinter Traefik

Forgejo mit Docker & Traefik aufsetzen: eigener Git-Server mit HTTPS, Repos per Web-UI, Klonen über HTTPS und SSH – die …

· 10 Min. Lesezeit

Das könnte dir auch schmecken