#!/bin/bash exec 9> /home/debian/backup.lock flock -n 9 || exit 1 nextcloud_disabled = 0 set -e # List all required tools REQUIRED_TOOLS=("xz" "gpg" "rsync" "rclone" "tar" "sed" "cut" "xargs") # Loop through and check each tool for tool in "${REQUIRED_TOOLS[@]}"; do if ! command -v "$tool" &> /dev/null; then echo "$tool is not installed. Please install it first." exit 1 fi done mkdir -p postgres_backup cleanup_services() { echo "Resuming normal operations..." # Disable Nextcloud maintenance mode if [nextcloud_disabled -eq 1] then docker exec -u www-data nextcloud_app php occ maintenance:mode --off || true fi # Start all services back up (using start instead of stop) docker start gitea jellyfin synapse-foxgirls || true rm -rf postgres_backup } trap cleanup_services EXIT INT TERM echo "Pausing services..." if [nextcloud_disabled -eq 1] then docker exec -u www-data nextcloud_app php occ maintenance:mode --on || true fi docker stop gitea jellyfin synapse-foxgirls || true ( source docker/synapse/.env docker exec postgres pg_dumpall -U "$PSQL_NAME" --globals-only > postgres_backup/globals.sql docker exec postgres pg_dump -U "$PSQL_NAME" -d "$PSQL_DB_NAME" > postgres_backup/synapse.sql ) ( source gitea/.env docker exec postgres pg_dump -U "$DB_UNAME" -d "$DB_NAME" > postgres_backup/gitea.sql ) ( source nextcloud/.env docker exec postgres pg_dump -U "$DB_UNAME" -d "$DB_NAME" > postgres_backup/nextcloud.sql ) BACKUP_FOLDER="/backups" BACKUP_DATE=$(date +"%Y-%m-%d_%H-%M") BASE_NAME="${BACKUP_FOLDER}/full_backup_${BACKUP_DATE}" mkdir "${BASE_NAME}_tmp" sudo rsync -avR --numeric-ids palworld/{compose.yaml,.env,palworld/Pal/Saved/SaveGames,adminPage} \ synapse-data2/{homeserver.yaml,homeserver.db,foxgirls.date.log.config,foxgirls.date.signing.key,media_store/local_content,media_store/local_thumbnails} \ docker/synapse/{.env,compose.yaml,element-call,livekit,redis_data,turn} \ uptime-kuma \ reverse_proxy \ nextcloud/{compose.yaml,Dockerfile,.env,nextcloud_data/config} \ jellyfin/{compose.yaml,mount.sh,cache,config} \ homepage \ gitea \ postgres_backup \ diun/compose.yaml \ wireguard \ picoshare \ "${BASE_NAME}_tmp/" #backup has been created, remove the cleanup trap, restore services before uploading backup cleanup_services cleanup_files() { if [[ -d "${BASE_NAME}_tmp" ]]; then sudo rm -rf "${BASE_NAME}_tmp" fi } trap cleanup_files EXIT INT TERM #compress, encrypt, and send the backup to b2 here source .env #BACKUP_PASS, BACKUP_REMOTE echo "Compressing and encrypting backup..." sudo tar -C "${BACKUP_FOLDER}" -cf - "full_backup_${BACKUP_DATE}_tmp" | \ xz -T0 | \ gpg --batch --yes --passphrase "$BACKUP_PASS" --pinentry-mode loopback -c -o "${BASE_NAME}.tar.xz.gpg" echo "Backup Created! ${BASE_NAME}.tar.xz.gpg" echo "Uploading backup..." rclone copy "${BASE_NAME}.tar.xz.gpg" "${BACKUP_REMOTE}" \ --log-file="$HOME/backup.log" \ --retries 3 echo "Backup uploaded!" #remove local backups once there are more then 10 echo "Evaluating local retention..." cd "$BACKUP_FOLDER" find . -maxdepth 1 -type f -name "full_backup_*.tar.xz.gpg" -printf '%T@ %p\n' | \ sort -rn | \ sed '1,10d' | \ cut -d' ' -f2- | \ xargs -I {} sudo rm -f {} #cleanup B2 echo "Evaluating remote retention..." rclone delete "${BACKUP_REMOTE}" --min-age 60d --rmdirs --log-file="$HOME/backup.log" echo "Backup Complete" curl -s -o /dev/null "${MONITORURL}" || true #todo make something to test bakcups #gpg --batch -d --passphrase "password_here" full_backup_2026-08-19_01-00.tar.xz.gpg | xz -d -T0 | tar xf -