====== Nextcloud-Backup-Skript ====== ===== Was macht dieses Skript? ===== Das Skript erstellt automatisch eine **Sicherung (Backup)** Ihrer Nextcloud-Instanz. Es werden sowohl alle hochgeladenen Dateien (Dokumente, Fotos usw.) als auch die dazugehörige Datenbank (Benutzer, Teilungen, Einstellungen) gesichert. Das Ergebnis ist eine einzige komprimierte ''.tar.gz''-Datei, die im Notfall zur Wiederherstellung verwendet werden kann. ===== Wann wird das Skript eingesetzt? ===== * **Manuell** – Ein Administrator führt es bei Bedarf aus. * **Automatisch** – Es kann z. B. täglich über einen Cron-Job (geplante Aufgabe) gestartet werden, um regelmäßige Backups zu gewährleisten. ===== Was wird genau gesichert? ===== * Das gesamte Nextcloud-Installationsverzeichnis (Programmdateien, Konfiguration, Apps) * Das ''data''-Verzeichnis (enthält alle Benutzerdateien, sofern es sich außerhalb der Installation befindet) * Ein vollständiger Export der Nextcloud-Datenbank (MySQL/MariaDB) ===== Welche Einstellungen sind wichtig? ===== Vor der ersten Nutzung müssen in der Skriptdatei zwei Pfade angepasst werden: ^ Variable ^ Bedeutung ^ | ''BACKUP_BASE'' | Ordner, in dem die Backup-Dateien gespeichert werden (z. B. ein externer USB-Stick oder ein Netzwerklaufwerk) | | ''MAX_BACKUPS'' | Wie viele alte Backups aufbewahrt werden sollen (ältere werden automatisch gelöscht) | ===== Benötigte Berechtigungen ===== Das Skript muss mit **Administratorrechten (root)** ausgeführt werden, da es auf geschützte Verzeichnisse und Dienste zugreift. ===== Was passiert während des Backups? ===== - Nextcloud wird in den **Wartungsmodus** versetzt – Benutzer können sich dann nicht einloggen und keine Änderungen vornehmen. Das stellt sicher, dass das Backup konsistent ist. - Ein Dump der Datenbank wird erstellt. - Alle Dateien und der Datenbank-Dump werden in ein ''.tar.gz''-Archiv gepackt. - Ältere Backups über der eingestellten Anzahl werden gelöscht. - Der Wartungsmodus wird deaktiviert – Nextcloud ist wieder normal erreichbar. ===== Wo finde ich Fehlermeldungen? ===== Alle Fehler werden in einer Logdatei festgehalten. Diese liegt im selben Ordner wie die Backups und heißt ''nextcloud.log''. Bei Problemen sollte der Administrator dort nachsehen. ===== Wichtige Hinweise ===== * **Backup-Medium:** Es wird dringend empfohlen, das Backup auf einem **anderen Gerät** (z. B. externer USB-Stick, NAS, separates Laufwerk) zu speichern. Wenn die Festplatte der Nextcloud defekt geht, wäre ein Backup auf derselben Platte nutzlos. * **Plattenplatz:** Das Skript prüft derzeit noch nicht automatisch, ob genug freier Speicherplatz vorhanden ist. Der Administrator sollte regelmäßig kontrollieren, dass das Zielverzeichnis nicht voll läuft. * **Debug-Modus:** Für detailliertere Ausgaben während der Ausführung kann die Variable ''debug'' im Skript auf ''1'' gesetzt werden. ===== Kurzanleitung zur Einrichtung ===== - Skriptdatei auf dem Server speichern (z. B. ''/usr/local/bin/backup_nextcloud.sh''). - Ausführbar machen: chmod +x /usr/local/bin/backup_nextcloud.sh - Die vier Hilfsskripte (''detect_web_apps.sh'', ''zeitdifferenz.sh'', ''limit_backups.sh'', ''in_arbeit.sh'') ebenfalls im Verzeichnis ''/usr/local/bin'' ablegen. - ''BACKUP_BASE'' und ''MAX_BACKUPS'' anpassen. - Testlauf als root: sudo /usr/local/bin/backup_nextcloud.sh - Bei Erfolg kann ein Cron-Job eingerichtet werden, z. B. täglich um 2 Uhr nachts: 0 2 * * * root /usr/local/bin/backup_nextcloud.sh ===== Wiederherstellung ===== Die erstellte ''.tar.gz''-Datei kann einfach in das gewünschte Verzeichnis entpackt werden (tar -xzf backupname.tar.gz). Anschließend muss der Datenbank-Dump eingespielt und ggf. die Konfiguration angepasst werden. Eine detaillierte Wiederherstellungsanleitung finden Sie in der Nextcloud-Dokumentation. ===== das Skript ===== ++++ backup_nextcloud.sh | #!/bin/bash # ==================================================== # Nextcloud Backup Script # ==================================================== # Beschreibung: # Erstellt ein vollständiges Backup der Nextcloud-Installation # inkl. Datenbank-Dump und verpackt alles in eine TGZ-Datei. # # https://chat.deepseek.com/a/chat/s/b683b7a5-0ad1-49b8-b63e-a11aff2b5e52 # # es gib ein logfile für alle Fehler die auftreten # die Meldungen kommen nur wenn debug eingeschaltet ist (debug > 0) # # ####### Speicherplatz berechnen !!!!!!!!!! ### benoetigter_Speicherplatz=$(tar -czf - datei "$(basename "$nc_path")" |wc -c) ### echo -e "benoetigter_Speicherplatz=$benoetigter_Speicherplatz" ### exit # ####### eigentlich sollte die Sicherung auf einem anderen Gerät erfolgen ### wenn das Laufwerk defekt ist, ist auch die Sicherung futsch ### Frage: Netzlaufwerk, ftp-Laufwerk, USB-Stick ???? # ####### die Funktion limit_backups sollte vor dem Anlegen der Backups ### aufgerufen werden damit bei grossen Backups beurteil werden kann ### wieviel Speicherplatz wahrscheinlich benötigt werden wird ### -- wenn schon ein Backup vorhanden ist ### -- steht die wahrscheinlich ja fest # # # # ######################################################## debug=0 backup_start=$(date +%s) ###### Pfade anpassen: ####################### ## wird in Zukunft durch die Funktion web_app_type ermittelt #~ NC_PATH="/var/www/html/nc.dcb-charlot.de" BACKUP_BASE="/home/pi/sicherung" MAX_BACKUPS=2 SKRIPTEVERZEICHNIS=/usr/local/bin ###### abgeleitete Variable ################## ## sourcen der Funktionsdateien --------------------- function funktionen_nachladen(){ if [[ -e "$1" ]];then source "$1" if [[ $? -ne 0 ]]; then echo "Sourcing fehlgeschlagen"; exit; fi else echo -e "die Datei $1 Funktionen wurde nicht gefunden" echo -e "das Programm wird beendet!\n\n" exit fi } funktionen_nachladen "${SKRIPTEVERZEICHNIS}/detect_web_apps.sh" funktionen_nachladen "${SKRIPTEVERZEICHNIS}/zeitdifferenz.sh" funktionen_nachladen "${SKRIPTEVERZEICHNIS}/limit_backups.sh" funktionen_nachladen "${SKRIPTEVERZEICHNIS}/in_arbeit.sh" nc_path=$(web_app_type 'nextcloud') # timestamp für den Archivnamen (Format: Jahr-Monat-Tag_Stunde-Minute-Sekunde) timestamp=$(date +"%Y%m%d_%H%M") backup_name="${nc_path##*/}-${timestamp}.tar.gz" backup_file="${BACKUP_BASE}/${backup_name}" LOG_FILE="$BACKUP_BASE/${nc_path##*/}.log" # Temporärer Speicherort für den Datenbank-Dump tmp_dump="${nc_path}/nextcloud_db_dump.sql" ## du_muss_root_sein if [[ $(id -u) -ne 0 ]];then [[ $debug -ne 0 ]] && echo -e "root Privilegien erforderlich!\n --> ${BASH_SOURCE##*/}:$LINENO\n\n"; echo -e "$timestamp root Privilegien erforderlich!\n --> ${BASH_SOURCE##*/}:$LINENO\n\n" >> $LOG_FILE exit; fi #~ if [[ debug -eq 9 ]];then if [[ debug -gt 0 ]];then echo -e "" echo -e " nc_path=$nc_path\n" echo -e "BACKUP_BASE=$BACKUP_BASE" echo -e "backup_file=$backup_file" echo -e " LOG_FILE=$LOG_FILE" echo -e "" echo -e "backup_name=$backup_name" echo -e " tmp_dump=$tmp_dump" echo -e "" fi #======================================================================= function linie { for ((i = 1 ; i < $(tput cols) ; i++));do echo -n "-"; done; echo;} ## gib die aktelle Fehlermeldung aus fehler_meldung() { if [[ $# -eq 0 ]];then echo -e "$timestamp Abbruch ohne Fehlermeldung" >> $LOG_FILE cleanup fi if [[ $debug -ne 0 ]];then echo -e "$timestamp $1"; fi echo -e "$timestamp $1" >> $LOG_FILE cleanup } # Funktion: Fehlerbehandlung und Wartungsmodus ausschalten cleanup() { if [ -f "$tmp_dump" ]; then rm -f "$tmp_dump" fi # Wartungsmodus deaktivieren (falls aktiv) if [ -f "${nc_path}/config/config.php" ]; then sudo -u www-data php "${nc_path}/occ" maintenance:mode --off &>/dev/null fi echo "$timestamp Backup abgebrochen oder fehlgeschlagen." >> $LOG_FILE if [[ $debug -ne 0 ]];then echo -e "\ndas Logfile ($LOG_FILE)" linie tail $LOG_FILE; linie fi exit 1 } # Trap für Abbruchsignale (Ctrl+C, Fehler) ## ruft die cleanup-Funktion auf ## trap cleanup ERR INT TERM #======================================================================= echo -e "Nextcloud-Backup ${nc_path}" in_arbeit "Start" # Prüfen, ob Nextcloud-Pfad existiert if [ ! -d "${nc_path}" ]; then fehler_meldung "Fehler: Nextcloud-Pfad '$nc_path' existiert nicht!" cleanup fi # Backup-Zielverzeichnis erstellen, falls nicht vorhanden mkdir -p "${BACKUP_BASE}" || { fehler_meldung "Fehler: Kann Zielverzeichnis '$BACKUP_BASE' nicht erstellen." cleanup } [[ $debug -ne 0 ]] && echo -e "===== Nextcloud Backup gestartet: $(date) ====="; # 1. Nextcloud in den Wartungsmodus versetzen [[ $debug -ne 0 ]] && echo -e "Wartungsmodus aktivieren..."; sudo -u www-data php "${nc_path}/occ" maintenance:mode --on &>/dev/null if [ $? -ne 0 ]; then fehler_meldung "Fehler: Kann Wartungsmodus nicht aktivieren." cleanup fi # 2. Datenbank-Zugangsdaten aus config.php extrahieren CONFIG_FILE="${nc_path}/config/config.php" if [ ! -f "${CONFIG_FILE}" ]; then fehler_meldung "Fehler: Nextcloud-config: ${CONFIG_FILE} nicht gefunden!" cleanup fi datadirectory=$(cat $CONFIG_FILE |grep datadirectory |sed 's/ //g' |cut -d"'" -f4) if [[ ! -e "${datadirectory}" ]];then fehler_meldung "Fehler: Nextcloud $datadirectory nicht gefunden!" cleanup fi # Absolute, aufgelöste Pfade (keine relativen, keine Symlinks) abs_nc=$(realpath "$nc_path") abs_data=$(realpath "$datadirectory") # Prüfen, ob data_dir innerhalb von nextcloud_dir liegt if [[ "$abs_data" == "$abs_nc"/* ]]; then [[ $debug -ne 0 ]] && echo -e "data-Verzeichnis liegt innerhalb der Nextcloud-Installation!"; datadirectory="" else [[ $debug -ne 0 ]] && echo -e "OK: data-Verzeichnis liegt außerhalb der Installation."; fi # Extrahiere 'dbname', 'dbuser', 'dbpassword' mit grep/sed DB_NAME=$(grep "'dbname'" "$CONFIG_FILE" | sed "s/.*'dbname' => '\([^']*\)'.*/\1/") DB_USER=$(grep "'dbuser'" "$CONFIG_FILE" | sed "s/.*'dbuser' => '\([^']*\)'.*/\1/") DB_PASS=$(grep "'dbpassword'" "$CONFIG_FILE" | sed "s/.*'dbpassword' => '\([^']*\)'.*/\1/") if [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASS" ]; then fehler_meldung "Fehler: Datenbank-Zugangsdaten konnten nicht ausgelesen werden." cleanup fi if [[ -z "noch nicht fertig" ]];then ## Überprfen ob das zu erwartende Backup-file noch auf des Medium passt MIN_FREIER_PLATZ=.80 prefix="${backup_file%${timestamp}.tar.gz}" SIZE=$(stat -c%s "$(ls -t ${prefix}*.tar.gz |head -n1)") freier_platz=$(df --block-size=1 --output=avail "$BACKUP_BASE" | tail -n1) prozent_frei=$(echo "scale=2; $SIZE * 100 / $freier_platz" | bc) echo "$SIZE Bytes" echo "$freier_platz Bytes verfügbar" echo "Das entspricht $prozent_frei des aktuell freien Platzes." echo -e "-------" # Verfügbarer und gesamter Speicherplatz im Zielverzeichnis (Medium) #~ freier_platz=$(df --block-size=1 --output=avail "$BACKUP_BASE" | tail -n1) exit fi # 3. MySQL-Dump erstellen [[ $debug -ne 0 ]] && echo -e "Erstelle Datenbank-Dump (${DB_NAME}) ..."; mysqldump --single-transaction --quick --skip-lock-tables \ -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$tmp_dump" if [ $? -ne 0 ] || [ ! -s "$tmp_dump" ]; then fehler_meldung "Fehler: Datenbank-Dump fehlgeschlagen oder leer." cleanup fi [[ $debug -ne 0 ]] && echo -e "Datenbank-Dump erfolgreich erstellt: $(du -h "$tmp_dump" | cut -f1)"; # 4. Alle Dateien (inkl. Dump) in ein TGZ-Archiv packen [[ $debug -ne 0 ]] && echo -e "Erstelle tar.gz-Archiv: $backup_name"; # Wechsle ins übergeordnete Verzeichnis von nc_path, damit der Pfad relativ wird # (Beim Entpacken entsteht wieder das Verzeichnis nc.dcb-charlot.de) cd "$(dirname "$nc_path")" || cleanup #~ tar -czf "$backup_file" "$(basename "$nc_path")" "$(basename "$datadirectory")" tar -czf "$backup_file" $nc_path $datadirectory $SKRIPTEVERZEICHNIS &>/dev/null if [ $? -ne 0 ]; then fehler_meldung "Fehler: Fehler beim Erstellen des Tar-Archivs." cleanup fi [[ $debug -ne 0 ]] && echo -e "Backup-Datei erstellt: $backup_file"; [[ $debug -ne 0 ]] && echo -e "Größe: $(du -h "$backup_file" | cut -f1)"; # 5. Temporären Dump löschen rm -f "$tmp_dump" ## Anzahl der Backups begranzen limit_backups "$backup_file" $MAX_BACKUPS "$timestamp" # 6. Wartungsmodus deaktivieren [[ $debug -ne 0 ]] && echo -e "Wartungsmodus deaktivieren..."; sudo -u www-data php "${nc_path}/occ" maintenance:mode --off &>/dev/null backup_ende=$(date +%s) backupdauer=$(zeitdifferenz "$backup_start" "$backup_ende") echo -e "\nDauer des Backups war ${backupdauer} \nes wurden $(du -h $backup_file |sed 's/\t\+/ /g;s/ \+/ /g'| cut -d' ' -f1 ) Speicherplatz belegt\n" in_arbeit "Ende" [[ $debug -ne 0 ]] && echo -e "===== Backup erfolgreich abgeschlossen: $(date) ====="; exit 0 ++++