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.
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
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.
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.
💶 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:
sudo apt update
sudo apt install -y resticPrüfe die Version:
restic versionrestic 0.18.0 compiled with go1.24.4 on linux/amd64Neuere Version bei Bedarf
/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:
sudo install -d -m 700 /etc/restic
openssl rand -base64 32 | sudo tee /etc/restic/password > /dev/null
sudo chmod 600 /etc/restic/passwordDer 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:
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 alsAWS_ACCESS_KEY_IDundAWS_SECRET_ACCESS_KEYin 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):
restic initcreated 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
/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:
restic backup /root/backup-demo --tag demono 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 savedBeim zweiten Lauf zeigt sich Restics Stärke: Es sichert nur die Änderungen (Deduplizierung). Ändert sich eine Datei und du sicherst erneut:
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 savedStatt 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:
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:
restic snapshotsID 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 snapshotsStelle einen kompletten Snapshot in ein Zielverzeichnis wieder her (nutze latest
für den neuesten oder eine konkrete ID):
restic restore latest --target /root/restore-testrestoring 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:00Brauchst du nur eine Datei, gibt es zwei Wege – gezielt diesen Pfad wiederherstellen:
restic restore latest --target /tmp/wiederher --include /root/backup-demo/config.yaml… oder die Datei direkt auf die Standardausgabe streamen, ganz ohne Umweg:
restic dump latest /root/backup-demo/config.yaml > /tmp/config.yamlZum 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:
restic checkusing 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 foundDie 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:
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:
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --pruneApplying 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 snapshotsDie 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):
# /etc/restic/restic.env
RESTIC_REPOSITORY=sftp:BACKUP_BENUTZER@DEIN_BACKUP_HOST:/backups/DEIN_SERVER
RESTIC_PASSWORD_FILE=/etc/restic/passwordDann 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"):
#!/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/nullsudo chmod 700 /usr/local/bin/restic-backup.shDer Dienst lädt die Environment-Datei und führt das Skript aus –
/etc/systemd/system/restic-backup.service:
[Service]
Type=oneshot
EnvironmentFile=/etc/restic/restic.env
ExecStart=/usr/local/bin/restic-backup.shUnd der Timer /etc/systemd/system/restic-backup.timer startet ihn täglich nachts:
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.targetPersistent=true holt einen verpassten Lauf (z. B. weil der Server nachts aus war)
beim nächsten Start nach. Aktivieren:
sudo systemctl daemon-reload
sudo systemctl enable --now restic-backup.timerPrüfe, wann der nächste Lauf ansteht:
systemctl list-timers restic-backup.timerNEXT 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
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:
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-testVergleiche 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-subsetregelmäß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 addzusä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?

Matomo cookielos selbst hosten: Analytics ohne Consent-Banner
Matomo 5.12 mit Docker & Traefik aufsetzen: datenschutzfreundliche Web-Analytics mit IP-Anonymisierung, ganz ohne Google …

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 …

Den ganzen Docker-Stack sicher aktuell halten
Update-Disziplin für deinen Docker-Stack: Versionen pinnen, mit Diun über Updates informiert werden, sicher einspielen, …

Immich selbst hosten: dein privates Foto-Backup hinter Traefik
Immich mit Docker hinter Traefik aufsetzen: die selbst gehostete Alternative zu Google Fotos – mit automatischem …

Paperless-ngx selbst hosten: papierloses Büro mit OCR
Paperless-ngx mit Docker hinter Traefik aufsetzen: Dokumente per OCR durchsuchbar archivieren – mit Volltextsuche, Tags …

Nextcloud selbst hosten: deine eigene Cloud hinter Traefik
Nextcloud mit Docker hinter Traefik aufsetzen: eigene Cloud für Dateien, Kalender und Kontakte – mit MariaDB, Redis und …

Vaultwarden: eigener Passwortmanager hinter Traefik
Vaultwarden selbst hosten: ein schlanker, Bitwarden-kompatibler Passwortmanager hinter Traefik mit HTTPS, Admin-Panel …
Das könnte dir auch schmecken

Fail2ban einrichten: Brute-Force-Angriffe automatisch blocken
Fail2ban überwacht deine Logs und sperrt IPs nach zu vielen Fehlversuchen – mit sicherer Whitelist für die eigene …

Linux-Benutzer, Gruppen & Dateirechte verstehen
Wer darf was auf deinem Server? Dieser Grundlagen-Guide erklärt Benutzer, Gruppen und Dateirechte an echten Befehlen – …

WireGuard-VPN einrichten: sicherer Zugang zum eigenen Server
Ein schlankes WireGuard-VPN nativ auf dem netcup-Server: Schlüssel, Server- und Client-Konfig, Firewall, Handy-QR – plus …