Backup & Restore
Regelmäßige Backups gehören zum Betrieb einer Instanz. Ein Server kann ausfallen, ein Update schiefgehen oder eine Fehlkonfiguration Daten beschädigen. Ohne Backup gibt es keine zweite Chance. Diese Seite zeigt, wie du FediSuite von Hand, automatisiert und extern sicherst und im Ernstfall vollständig wiederherstellst.
Auf dieser Seite
Was muss gesichert werden?
./postgres/
(PostgreSQL-Datenbank)
Nutzer*innen, Beiträge, Entwürfe, verbundene Fediverse-Konten, Einstellungen, Analysedaten. Das mit Abstand Wichtigste.
Methode: pg_dump (nicht Verzeichniskopie)
./uploads/
(Anhänge)
Mediendateien und PDFs von Beiträgen und Entwürfen. Seit FediSuite 2.0 bleiben die Dateien veröffentlichter Beiträge erhalten, damit sie als Entwurf wiederverwendet werden können, das Verzeichnis wächst entsprechend.
Methode: tar-Archiv
.env
(Konfigurationsdatei)
Alle Passwörter, Secrets und Einstellungen. Der JWT_SECRET darin verschlüsselt gespeicherte Zwei-Faktor-Geheimnisse: Ohne den ursprünglichen Wert lassen sie sich nach einem Restore nicht mehr entschlüsseln.
Methode: verschlüsselte Kopie
./logs/
(Audit-Logs)
Sicherheitsrelevante Ereignisse als JSON-Zeilen in monatlichen Dateien. Nur nötig, wenn du sie aufbewahren musst.
Methode: tar-Archiv
./plugins/
(Installierte Plugins)
Selbst installierte Plugins. Sie lassen sich im Zweifel neu herunterladen, ein Backup ist trotzdem sinnvoll.
Methode: tar-Archiv
docker-compose.yml
(Compose-Konfiguration)
Die Stack-Definition inklusive eigener Anpassungen oder einer docker-compose.override.yml. Die mitgelieferte Datei kommt jederzeit neu aus dem Repository.
Methode: einfache Kopie
./letsencrypt/
(Traefik-Zertifikate)
Nur bei Traefik im selben Stack (Szenario 2): die acme.json mit den Zertifikaten. Sie lässt sich neu ausstellen, ein Backup spart Rate-Limit-Ärger.
Methode: tar-Archiv
Die drei Grundsätze
3-2-1
Die 3-2-1-Regel
Mindestens 3 Kopien auf 2 verschiedenen Medien oder Systemen, davon 1 an einem anderen Ort. Ein Backup auf demselben Server schützt nicht vor dem Verlust des Servers.
∞
Automatisierung
Ein Backup, das von Hand angestoßen werden muss, wird irgendwann vergessen. Richte einen Cron-Job ein, der täglich sichert, und prüfe gelegentlich sein Log.
Restore testen
Ein nicht getestetes Backup ist unsicher. Prüfe regelmäßig, ob du daraus wiederherstellen kannst, bevor der Ernstfall eintritt.
Datenbank sichern (pg_dump)
Solange PostgreSQL läuft, solltest du die Datenbank nicht durch Kopieren von ./postgres/ sichern. Die Datendateien können dabei in einem inkonsistenten Zustand sein und nach einer Wiederherstellung beschädigt wirken.
Der richtige Weg ist pg_dump, das PostgreSQL-Werkzeug für logische Backups. Es erzeugt einen konsistenten Snapshot als SQL-Dump, während die Datenbank läuft, und ist unabhängig von der Dateistruktur. Die Beispiele nutzen Benutzer und Datenbank fedisuite aus der .env.example. Passe sie an, wenn du andere POSTGRES_*-Werte gesetzt hast.
Einfacher Dump (unkomprimiert)
Erzeugt eine lesbare SQL-Datei, gut zum Prüfen des Inhalts.
docker compose exec -T db \
pg_dump -U fedisuite fedisuite \
> backup_$(date +%Y-%m-%d).sql
Komprimierter Dump empfohlen
Gzip-komprimiert, deutlich kleiner und direkt für die externe Speicherung geeignet.
docker compose exec -T db \
pg_dump -U fedisuite fedisuite \
| gzip > backup_$(date +%Y-%m-%d_%H-%M-%S).sql.gz
Backup inhaltlich prüfen
Zeigt die ersten Zeilen des Dumps, ohne ihn vollständig zu entpacken.
gunzip -c backup_2026-10-01_03-00-00.sql.gz | head -30
umask 077) und verschlüsselte Ablage außerhalb des Servers.
./postgres/ kopieren? PostgreSQL hält die Daten im laufenden Betrieb nicht in einem Zustand auf der Platte, der sich von außen konsistent kopieren ließe. Ein Verzeichnis-Snapshot kann unvollständige Transaktionen oder halb geschriebene Seiten enthalten. pg_dump fragt die Datenbank über das normale Protokoll ab und bekommt dadurch konsistente Daten. Eine Verzeichniskopie ist nur bei gestoppter Datenbank (docker compose stop db) verlässlich, und sie gilt nur für dieselbe PostgreSQL-Hauptversion.
Dateien sichern
Neben der Datenbank müssen Uploads und Konfiguration gesichert werden. Uploads können viel Speicher belegen, plane das bei der Wahl des Backup-Ziels ein.
Uploads archivieren
Erstellt ein komprimiertes Archiv des Upload-Verzeichnisses.
tar -czf uploads_$(date +%Y-%m-%d_%H-%M-%S).tar.gz ./uploads/
.env sichern
Die .env enthält Passwörter und Secrets, sichere sie separat und verschlüsselt.
# Einfache Kopie (nur wenn das Ziel selbst verschlüsselt ist)
cp .env backups/env_$(date +%Y-%m-%d)
# Verschlüsselt mit GPG (für externe Speicherung empfohlen)
gpg --symmetric --cipher-algo AES256 \
--output backups/env_$(date +%Y-%m-%d).gpg .env
Plugins, Logs und Compose-Datei sichern
Optional, aber empfehlenswert bei eigenen Anpassungen.
tar -czf plugins_$(date +%Y-%m-%d).tar.gz ./plugins/
tar -czf logs_$(date +%Y-%m-%d).tar.gz ./logs/
cp docker-compose.yml backups/docker-compose_$(date +%Y-%m-%d).yml
Automatisches Backup-Skript
Das Skript sichert Datenbank, Uploads und Konfiguration in einem Schritt, versieht jedes Backup mit einem Zeitstempel und räumt alte Backups auf. Passe FEDISUITE_DIR und BACKUP_DIR an deine Pfade an.
#!/bin/bash
set -euo pipefail
umask 077
# ── Konfiguration ────────────────────────────────────────────────
FEDISUITE_DIR="/opt/fedisuite" # Pfad zum FediSuite-Verzeichnis
BACKUP_DIR="/var/backups/fedisuite" # Ziel für Backups
KEEP_DAYS=7 # tägliche Backups älter als X Tage löschen
DB_NAME="fedisuite"
DB_USER="fedisuite"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
DAILY="$BACKUP_DIR/daily"
LOG_PREFIX="[fedisuite-backup][$DATE]"
# ── Vorbereitung ─────────────────────────────────────────────────
mkdir -p "$DAILY" "$BACKUP_DIR/weekly" "$BACKUP_DIR/monthly"
cd "$FEDISUITE_DIR"
echo "$LOG_PREFIX Start"
# ── 1. Datenbank (pg_dump) ───────────────────────────────────────
echo "$LOG_PREFIX Sichere Datenbank..."
docker compose exec -T db \
pg_dump -U "$DB_USER" "$DB_NAME" \
| gzip > "$DAILY/db_${DATE}.sql.gz"
gzip -t "$DAILY/db_${DATE}.sql.gz"
echo "$LOG_PREFIX ✓ Datenbank: db_${DATE}.sql.gz ($(du -sh "$DAILY/db_${DATE}.sql.gz" | cut -f1))"
# ── 2. Uploads ───────────────────────────────────────────────────
echo "$LOG_PREFIX Sichere Uploads..."
tar -czf "$DAILY/uploads_${DATE}.tar.gz" \
-C "$FEDISUITE_DIR" uploads/
echo "$LOG_PREFIX ✓ Uploads: uploads_${DATE}.tar.gz ($(du -sh "$DAILY/uploads_${DATE}.tar.gz" | cut -f1))"
# ── 3. Konfiguration ─────────────────────────────────────────────
echo "$LOG_PREFIX Sichere Konfiguration..."
cp "$FEDISUITE_DIR/.env" "$DAILY/env_${DATE}"
cp "$FEDISUITE_DIR/docker-compose.yml" "$DAILY/compose_${DATE}.yml"
echo "$LOG_PREFIX ✓ .env und docker-compose.yml gesichert"
# ── 4. Wöchentlich und monatlich aufbewahren ───────────────────────────
if [ "$(date +%u)" = "7" ]; then
cp "$DAILY/db_${DATE}.sql.gz" "$BACKUP_DIR/weekly/"
fi
if [ "$(date +%d)" = "01" ]; then
cp "$DAILY/db_${DATE}.sql.gz" "$BACKUP_DIR/monthly/"
fi
# ── 5. Alte Backups bereinigen ───────────────────────────────────
echo "$LOG_PREFIX Bereinige Backups (${KEEP_DAYS}d / 28d / 90d)..."
find "$DAILY" -maxdepth 1 -type f -mtime "+$KEEP_DAYS" -delete
find "$BACKUP_DIR/weekly" -maxdepth 1 -type f -mtime +28 -delete
find "$BACKUP_DIR/monthly" -maxdepth 1 -type f -mtime +90 -delete
echo "$LOG_PREFIX Backup erfolgreich abgeschlossen."
ls -lh "$DAILY" | tail -10
Skript installieren und ausführbar machen
Läuft als root oder als Benutzer mit Zugriff auf Docker.
# Skript erstellen
nano /usr/local/bin/fedisuite-backup.sh
# Ausführbar machen
chmod +x /usr/local/bin/fedisuite-backup.sh
# Einmalig testen
/usr/local/bin/fedisuite-backup.sh
Cron-Job einrichten
Ein Cron-Job führt das Skript automatisch und regelmäßig aus. Öffne die Crontab des Benutzers, unter dem das Skript laufen soll, und füge einen Eintrag hinzu:
crontab -e
Füge eine der folgenden Zeilen ein, je nach gewünschter Häufigkeit:
# Täglich um 03:00 Uhr (empfohlen)
0 3 * * * /usr/local/bin/fedisuite-backup.sh >> /var/log/fedisuite-backup.log 2>&1
# Zweimal täglich: 03:00 und 15:00 Uhr
0 3,15 * * * /usr/local/bin/fedisuite-backup.sh >> /var/log/fedisuite-backup.log 2>&1
Backup-Log prüfen
Prüfe regelmäßig, ob die Backups tatsächlich durchlaufen. Das Skript bricht bei jedem Fehler ab.
tail -50 /var/log/fedisuite-backup.log
Backup-Rotation
Ohne Rotation wächst das Backup-Verzeichnis unbegrenzt. Das Skript oben bewahrt die täglichen Backups KEEP_DAYS Tage auf, kopiert sonntags und am Monatsersten den Datenbank-Dump in weekly/ und monthly/ und löscht dort Dateien nach 28 bzw. 90 Tagen. Die Aufbewahrungszeiten passt du an den Stellen KEEP_DAYS, -mtime +28 und -mtime +90 an.
- •
/var/backups/fedisuite/daily/: Datenbank, Uploads und Konfiguration der letzten Tage - •
/var/backups/fedisuite/weekly/: wöchentliche Datenbank-Dumps der letzten 4 Wochen - •
/var/backups/fedisuite/monthly/: monatliche Datenbank-Dumps der letzten 3 Monate
Backups extern speichern
Ein Backup auf demselben Server schützt nicht vor Serverausfall, Diebstahl oder Problemen im Rechenzentrum. Übertrage Backups regelmäßig an ein externes Ziel. rclone ist dafür ein gängiges Werkzeug, es spricht viele Speicherdienste und SFTP mit einheitlicher Syntax. Alternativ funktionieren rsync oder borg auf einen eigenen Server.
rclone installieren
Über die Paketverwaltung deiner Distribution, zum Beispiel unter Debian und Ubuntu:
sudo apt install rclone
Remote-Ziel konfigurieren
Interaktiver Assistent: Wähle deinen Anbieter, zum Beispiel SFTP oder S3-kompatiblen Speicher.
rclone config
Backups hochladen
sync macht das Ziel zum Spiegel des lokalen Verzeichnisses und löscht dort auch Dateien, die lokal durch die Rotation verschwunden sind. Soll das Ziel länger aufbewahren als der Server, nimm rclone copy.
# Beispiel: SFTP-Ziel namens "backup"
rclone sync /var/backups/fedisuite backup:fedisuite-backups --progress
# Ziel behält auch lokal gelöschte Backups
rclone copy /var/backups/fedisuite backup:fedisuite-backups --progress
Hänge den Upload ans Ende des Backup-Skripts, damit jede Sicherung automatisch extern abgelegt wird:
# ── 6. Extern übertragen ─────────────────────────────────────────
echo "$LOG_PREFIX Übertrage Backups extern..."
rclone copy "$BACKUP_DIR" backup:fedisuite-backups \
--quiet --log-level ERROR
echo "$LOG_PREFIX ✓ Externe Übertragung abgeschlossen"
.env enthält Passwörter und den JWT-Secret, der Datenbank-Dump Passwort-Hashes und Konto-Tokens. Verschlüssele beides vor der externen Übertragung, zum Beispiel mit GPG, oder nutze ein Ziel, das clientseitig verschlüsselt (rclone crypt).
Restore: Schritt für Schritt
Im Ernstfall, etwa nach einem fehlgeschlagenen Update, einem beschädigten Dateisystem oder einem Serverwechsel, stellst du FediSuite so wieder her. Führe die Schritte in dieser Reihenfolge aus.
Stack stoppen
docker compose down
Konfiguration wiederherstellen (falls nötig)
Der ursprüngliche JWT_SECRET muss erhalten bleiben, sonst sind Logins und gespeicherte Zwei-Faktor-Geheimnisse ungültig.
# .env aus dem Backup zurückkopieren
cp /var/backups/fedisuite/daily/env_DATUM .env
# Oder entschlüsseln, falls mit GPG gesichert
gpg --decrypt /var/backups/fedisuite/env_DATUM.gpg > .env
Nur den Datenbankcontainer starten
PostgreSQL muss laufen, bevor du Daten einspielst. Die App startet erst in Schritt 7.
docker compose up -d db
# Warten, bis der Healthcheck besteht
docker compose ps
Bestehende Datenbank leeren
docker compose exec -T db \
psql -U fedisuite postgres \
-c "DROP DATABASE IF EXISTS fedisuite;"
docker compose exec -T db \
psql -U fedisuite postgres \
-c "CREATE DATABASE fedisuite;"
Datenbank einspielen
# Komprimierten Dump einspielen
gunzip -c /var/backups/fedisuite/daily/db_DATUM.sql.gz \
| docker compose exec -T db \
psql -v ON_ERROR_STOP=1 -U fedisuite fedisuite
# Unkomprimierten Dump einspielen
docker compose exec -T db \
psql -v ON_ERROR_STOP=1 -U fedisuite fedisuite \
< /var/backups/fedisuite/daily/db_DATUM.sql
Uploads wiederherstellen
# Bestehenden Uploads-Ordner beiseitelegen (falls vorhanden)
[ -d "./uploads" ] && mv ./uploads ./uploads.old
# Aus dem Backup wiederherstellen
tar -xzf /var/backups/fedisuite/daily/uploads_DATUM.tar.gz -C ./
Gesamten Stack starten
docker compose up -d
docker compose logs -f app
Die App führt init-db.js aus (idempotent: legt nur fehlende Strukturen an, bestehende Daten bleiben) und bringt dabei auch einen Dump aus einer älteren Version auf das aktuelle Schema. Danach starten die Worker.