Installation

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.

Was muss gesichert werden?

./postgres/ (PostgreSQL-Datenbank)
Kritisch

Nutzer*innen, Beiträge, Entwürfe, verbundene Fediverse-Konten, Einstellungen, Analysedaten. Das mit Abstand Wichtigste.

Methode: pg_dump (nicht Verzeichniskopie)

./uploads/ (Anhänge)
Wichtig

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)
Kritisch

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)
Optional

Sicherheitsrelevante Ereignisse als JSON-Zeilen in monatlichen Dateien. Nur nötig, wenn du sie aufbewahren musst.

Methode: tar-Archiv

./plugins/ (Installierte Plugins)
Optional

Selbst installierte Plugins. Sie lassen sich im Zweifel neu herunterladen, ein Backup ist trotzdem sinnvoll.

Methode: tar-Archiv

docker-compose.yml (Compose-Konfiguration)
Optional

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)
Optional

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
Der Dump ist vertraulich: Er enthält unter anderem Passwort-Hashes und die Zugangs-Tokens der verbundenen Konten. Behandle ihn wie ein Passwort: restriktive Dateirechte (zum Beispiel umask 077) und verschlüsselte Ablage außerhalb des Servers.
Warum nicht einfach ./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.

/usr/local/bin/fedisuite-backup.sh
#!/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:

bash
crontab -e

Füge eine der folgenden Zeilen ein, je nach gewünschter Häufigkeit:

crontab
# 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:

fedisuite-backup.sh: Ergänzung am Ende
# ── 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"
Sicherheit: Die .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.

1

Stack stoppen

docker compose down
2

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
3

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
4

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;"
Achtung: Dieser Schritt löscht alle aktuellen Datenbankdaten unwiderruflich. Prüfe, dass du das richtige Backup-Datum gewählt hast. Auf einem frisch angelegten Datenverzeichnis ist er nicht nötig.
5

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
6

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 ./
7

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.