Backup und Monitoring: Damit der Server nicht im Stillen stirbt

Dein Server läuft. nginx, MariaDB, PHP — alles eingerichtet, alles funktioniert. Und genau jetzt, wo alles gut aussieht, passieren die Fehler, die am teuersten werden: keine Backups eingerichtet, kein Monitoring aktiviert, und drei Monate später fällt die Festplatte aus. Diese Anleitung zeigt dir, wie du beides von Anfang an richtig aufsetzt.

Warum Backups nicht optional sind

Es gibt zwei Arten von Administratoren: Die, die schon mal Daten verloren haben, und die, die es noch vor sich haben. Hardware fällt aus, Software hat Bugs, Menschen machen Fehler. Die Frage ist nicht ob, sondern wann. Und ein Backup, das du nie getestet hast, ist kein Backup — es ist Hoffnung. Hoffnung ist keine Strategie für den Produktivbetrieb.

Datenbank-Backup per Cron

Die Datenbank ist der kritischste Teil jeder Webanwendung. Dateien kannst du aus dem Repository wiederherstellen, Uploads aus dem CDN — aber die Datenbank ist einzigartig. Jede Bestellung, jeder Inhalt, jede Konfiguration lebt in der Datenbank. Deshalb bekommt sie ein eigenes, tägliches Backup.

Das Backup-Skript ist bewusst einfach gehalten — komplexe Lösungen, die niemand versteht, werden im Ernstfall zum Problem. Das Backup-Verzeichnis gehört Root und ist nur für Root lesbar, weil Datenbank-Dumps Benutzerkonten, Passwort-Hashes und E-Mail-Adressen enthalten.

sudo mkdir -p /var/backups/mariadb
sudo chown root:root /var/backups/mariadb
sudo chmod 700 /var/backups/mariadb
sudo nano /usr/local/bin/backup-db.sh
#!/bin/bash
BACKUP_DIR="/var/backups/mariadb"
DATUM=$(date +%Y-%m-%d_%H-%M)
AUFBEWAHREN=14

# Alle Datenbanken sichern
mariadb-dump --all-databases --single-transaction --quick \
  | gzip > "${BACKUP_DIR}/all-databases_${DATUM}.sql.gz"

# Alte Backups löschen
find "${BACKUP_DIR}" -name "*.sql.gz" -mtime +${AUFBEWAHREN} -delete

echo "[$(date)] Backup abgeschlossen: all-databases_${DATUM}.sql.gz"

--single-transaction sorgt dafür, dass das Backup einen konsistenten Snapshot der Datenbank enthält, ohne laufende Transaktionen zu blockieren. Ohne diese Option kann ein Backup inkonsistente Daten enthalten — etwa eine Bestellung ohne die zugehörigen Positionen. --quick verhindert, dass der gesamte Dump im Arbeitsspeicher gehalten wird, was bei großen Datenbanken den Server in die Knie zwingen kann.

Das Skript bekommt chmod 700 und läuft als Cron-Job jede Nacht um 3 Uhr — zu einer Zeit, in der der Server wenig Last hat:

0 3 * * * /usr/local/bin/backup-db.sh >> /var/log/backup-db.log 2>&1

Datei-Backup

Neben der Datenbank brauchst du ein Backup der Dateien, die nicht im Repository liegen — Uploads, Konfigurationsdateien, SSL-Zertifikate:

#!/bin/bash
BACKUP_DIR="/var/backups/files"
DATUM=$(date +%Y-%m-%d_%H-%M)
AUFBEWAHREN=7

mkdir -p "${BACKUP_DIR}"

tar -czf "${BACKUP_DIR}/webroot_${DATUM}.tar.gz" \
  /var/www/ \
  /etc/nginx/ \
  /etc/letsencrypt/ \
  /etc/php/ \
  2>/dev/null

find "${BACKUP_DIR}" -name "*.tar.gz" -mtime +${AUFBEWAHREN} -delete

echo "[$(date)] Datei-Backup abgeschlossen: webroot_${DATUM}.tar.gz"

Datenbank-Dumps sind klein und werden 14 Tage aufbewahrt, Datei-Backups sind groß und reichen für 7 Tage. Aber ein Backup auf dem gleichen Server ist nur die halbe Miete — wenn der Server ausfällt, sind die Backups ebenfalls weg. Deshalb gehört mindestens eine Kopie auf ein anderes System.

# Beispiel: rsync auf einen Backup-Server
rsync -avz --delete /var/backups/ backup@[BACKUP-SERVER-IP]:/backups/[SERVER-NAME]/

Ob rsync, rclone oder S3-kompatiblen Object Storage — entscheidend ist, dass die Offsite-Kopie automatisch, verschlüsselt und regelmäßig getestet wird.

Monitoring — sehen, bevor es knallt

Ein Server kann wochen- oder monatelang laufen, während sich ein Problem langsam aufbaut. Die Festplatte füllt sich, der RAM wird knapp, ein Dienst ist abgestürzt und wurde nicht neu gestartet. Ohne Monitoring merkst du das erst, wenn die Website nicht mehr erreichbar ist — und dann ist es ein Notfall statt einer geplanten Wartung.

Vier Werte sind absolut kritisch: Festplattenbelegung (häufigster Grund für plötzliche Ausfälle), RAM-Auslastung, CPU-Load und Dienststatus von nginx, PHP-FPM und MariaDB.

Bevor du ein großes Monitoring-System aufsetzt, hilft ein einfaches Skript, das die kritischen Werte prüft und bei Problemen per Mail warnt:

#!/bin/bash
DISK_LIMIT=85
MAIL="admin@[deine-domain.de]"
HOSTNAME=$(hostname)

# Festplattenbelegung prüfen
DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt "$DISK_LIMIT" ]; then
    echo "[WARNUNG] Festplatte bei ${DISK_USAGE}% auf ${HOSTNAME}" \
      | mail -s "Disk Warning: ${HOSTNAME}" "$MAIL"
fi

# Dienste prüfen
for SERVICE in nginx php8.3-fpm mariadb; do
    if ! systemctl is-active --quiet "$SERVICE"; then
        echo "[KRITISCH] ${SERVICE} ist nicht aktiv auf ${HOSTNAME}" \
          | mail -s "Service Down: ${HOSTNAME}" "$MAIL"
    fi
done

echo "[$(date)] Health-Check abgeschlossen"

Dieses Skript prüft alle 15 Minuten, ob die Festplatte sich dem Limit nähert und ob die drei Kerndienste laufen. Es ersetzt kein echtes Monitoring, aber es fängt die häufigsten Probleme ab, bevor sie zum Ausfall werden.

*/15 * * * * /usr/local/bin/health-check.sh >> /var/log/health-check.log 2>&1

Prometheus und Grafana — für den nächsten Schritt

Das Health-Check-Skript ist ein Anfang, aber für mehrere Server brauchst du ein echtes Monitoring-System. Prometheus sammelt Metriken, Grafana macht sie sichtbar — zusammen bilden sie den Standard für Server-Monitoring. Prometheus fragt in regelmäßigen Abständen Exporter ab, und du siehst Trends, bevor sie zu Problemen werden.

# Node Exporter installieren (liefert System-Metriken an Prometheus)
sudo apt install -y prometheus-node-exporter
sudo systemctl enable prometheus-node-exporter

Die vollständige Einrichtung sprengt den Rahmen dieses Artikels, aber der Node Exporter ist der erste Schritt — einen Prometheus-Server kannst du jederzeit nachträglich anbinden.

Der Server ist komplett

In fünf Schritten hast du einen VPS von einer leeren Ubuntu-Installation zu einem produktionsfähigen Webserver aufgebaut. Das ist kein einmaliger Aufwand — das ist die Basis, die jeder Server braucht. Egal ob Shopware-Shop, WordPress-Blog oder eigene Webanwendung: Diese Grundlagen ändern sich nicht. Was sich ändert, sind die Anwendungen darauf — und die kannst du jetzt installieren.

Die gezeigten Code-Beispiele dienen zur Veranschaulichung. Nutzung auf eigene Verantwortung. Mehr dazu