#!/usr/bin/env bash set -euo pipefail source ./lib.sh log "Backup/Restore – Tools, Config & Timer (installer.env) …" # ───────────────────────────────────────────────────────────── # 1) installer.env laden (ENV > installer.env > Defaults) # ───────────────────────────────────────────────────────────── if [[ -f /etc/mailwolt/installer.env ]]; then # automatisch exportieren, damit ${VAR} später überall wirkt set -a # shellcheck disable=SC1091 source /etc/mailwolt/installer.env set +a else log "[i] /etc/mailwolt/installer.env nicht gefunden – nutze Defaults." fi # ───────────────────────────────────────────────────────────── # 2) Pfade & Defaults (werden durch ENV/installer.env überschrieben) # ───────────────────────────────────────────────────────────── CONF_DIR="/etc/mailwolt" CONF_FILE="${CONF_DIR}/backup.conf" BIN_DIR="/usr/local/sbin" UNIT_DIR="/etc/systemd/system" APP_DIR="${APP_DIR:-/var/www/mailwolt}" # DB-Parameter aus installer.env (bzw. ENV) oder Fallbacks DB_HOST="${DB_HOST:-127.0.0.1}" DB_NAME="${DB_NAME:-mailwolt}" DB_USER="${DB_USER:-mailwolt}" DB_PASS="${DB_PASS:-}" # Backup-Settings aus installer.env (bzw. ENV) BACKUP_DIR="${BACKUP_DIR:-/var/backups/mailwolt}" BACKUP_RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-7}" BACKUP_USE_ZSTD="${BACKUP_USE_ZSTD:-1}" BACKUP_ENABLED="${BACKUP_ENABLED:-0}" # 0|1 BACKUP_INTERVAL="${BACKUP_INTERVAL:-daily}" # daily|weekly|monthly install -d -m 0755 "$CONF_DIR" "$BACKUP_DIR" # ───────────────────────────────────────────────────────────── # 3) /etc/mailwolt/backup.conf (von UI/APP überschreibbar) # ───────────────────────────────────────────────────────────── cat > "$CONF_FILE" < "${BIN_DIR}/mailwolt-backup" <<'EOSH' #!/usr/bin/env bash set -euo pipefail log(){ echo "[$(date -Is)] $*"; } # Konfiguration laden (ENV > Datei) CONF="/etc/mailwolt/backup.conf" [[ -f "$CONF" ]] && # shellcheck disable=SC1090 source "$CONF" APP_DIR="${APP_DIR:-/var/www/mailwolt}" BACKUP_DIR="${BACKUP_DIR:-/var/backups/mailwolt}" RETENTION_DAYS="${RETENTION_DAYS:-7}" USE_ZSTD="${USE_ZSTD:-1}" MYSQL_DB="${MYSQL_DB:-mailwolt}" MYSQL_USER="${MYSQL_USER:-mailwolt}" MYSQL_PASS="${MYSQL_PASS:-}" MYSQL_HOST="${MYSQL_HOST:-127.0.0.1}" MYSQL_PORT="${MYSQL_PORT:-3306}" STATE_DIR="/var/lib/mailwolt" STATUS_FILE="${STATE_DIR}/backup.status" install -d -m 0755 "$STATE_DIR" "$BACKUP_DIR" START_TS="$(date +%s)" TS="$(date -u +%Y%m%dT%H%M%SZ)" TMP="$(mktemp -d /tmp/mwbackup.XXXXXX)" trap 'rm -rf "$TMP"' EXIT fail(){ local msg="${1:-backup failed}" local now="$(date -Is)" { echo "time=${now}" echo "size=0" echo "dur=$(( $(date +%s) - START_TS ))s" echo "ok=0" echo "error=${msg}" } > "$STATUS_FILE" echo "[$now] ${msg}" >&2 exit 1 } trap 'fail "unexpected error (exit $?)"' ERR OUT="${BACKUP_DIR}/mailwolt-${TS}.tar" log "⇒ starte Backup in $OUT …" # 1) DB log " • mysqldump …" MYSQL_PWD="$MYSQL_PASS" mysqldump \ -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" \ --single-transaction --routines --events --triggers \ "$MYSQL_DB" > "$TMP/mysql.sql" # 2) Maildir log " • Maildir …" tar -C / -cf "$TMP/mail.tar" var/mail/vhosts 2>/dev/null || true # 3) App (ohne heavy dirs) log " • App …" tar -C / -cf "$TMP/app.tar" \ --exclude='var/www/mailwolt/vendor' \ --exclude='var/www/mailwolt/node_modules' \ --exclude='var/www/mailwolt/public/build' \ var/www/mailwolt # 4) Configs log " • Configs …" mkdir -p "$TMP/files" cp -a /etc/mailwolt "$TMP/files/" 2>/dev/null || true cp -a /etc/postfix "$TMP/files/" 2>/dev/null || true cp -a /etc/dovecot "$TMP/files/" 2>/dev/null || true cp -a /etc/opendkim "$TMP/files/" 2>/dev/null || true cp -a /etc/opendmarc "$TMP/files/" 2>/dev/null || true cp -a /etc/rspamd "$TMP/files/" 2>/dev/null || true cp -a /etc/ssl/ui "$TMP/files/" 2>/dev/null || true tar -C "$TMP" -cf "$TMP/files.tar" files # 5) Paket log " • Archiviere …" tar -C "$TMP" -cf "$OUT" mysql.sql mail.tar app.tar files.tar # 6) Komprimieren (optional) if [[ "${USE_ZSTD:-1}" = "1" ]] && command -v zstd >/dev/null 2>&1; then log " • komprimiere (zstd) …" zstd -f --rm -19 "$OUT" OUT="${OUT}.zst" fi # 7) Retention if [[ "$RETENTION_DAYS" =~ ^[0-9]+$ ]]; then log " • Retention: lösche älter als ${RETENTION_DAYS} Tage …" find "$BACKUP_DIR" -type f -mtime +"$RETENTION_DAYS" -name 'mailwolt-*' -delete || true fi # 8) Statusfile fürs UI SIZE_BYTES="$(stat -c '%s' "$OUT" 2>/dev/null || echo 0)" { echo "time=$(date -Is)" echo "size=${SIZE_BYTES}" echo "dur=$(( $(date +%s) - START_TS ))s" echo "ok=1" echo "file=${OUT}" } > "$STATUS_FILE" chmod 0644 "$STATUS_FILE" 2>/dev/null || true log "[✓] Backup fertig: $OUT" EOSH chmod 0755 "${BIN_DIR}/mailwolt-backup" # ───────────────────────────────────────────────────────────── # 5) /usr/local/sbin/mailwolt-restore # ───────────────────────────────────────────────────────────── cat > "${BIN_DIR}/mailwolt-restore" <<'EOSH' #!/usr/bin/env bash set -euo pipefail log(){ echo "[$(date -Is)] $*"; } ARCHIVE="${1:-}" [[ -n "$ARCHIVE" ]] || { echo "Usage: mailwolt-restore "; exit 1; } [[ -f "$ARCHIVE" ]] || { echo "Backup nicht gefunden: $ARCHIVE"; exit 1; } TMP="$(mktemp -d /tmp/mwrestore.XXXXXX)" trap 'rm -rf "$TMP"' EXIT case "$ARCHIVE" in *.zst) zstd -d -c "$ARCHIVE" > "$TMP/backup.tar" ;; *) cp -a "$ARCHIVE" "$TMP/backup.tar" ;; esac log "⇒ entpacke …" tar -C "$TMP" -xf "$TMP/backup.tar" # Reihenfolge: DB → App → Mail → Config if [[ -f "$TMP/mysql.sql" ]]; then log " • MySQL wiederherstellen …" mysql < "$TMP/mysql.sql" fi if [[ -f "$TMP/app.tar" ]]; then log " • App → /var/www/mailwolt …" tar -C / -xf "$TMP/app.tar" fi if [[ -f "$TMP/mail.tar" ]]; then log " • Maildir → /var/mail/vhosts …" tar -C / -xf "$TMP/mail.tar" fi if [[ -f "$TMP/files.tar" ]]; then log " • Configs → /etc/* …" tar -C / -xf "$TMP/files.tar" fi log "[✓] Restore abgeschlossen." EOSH chmod 0755 "${BIN_DIR}/mailwolt-restore" log "[✓] Tools installiert: ${BIN_DIR}/mailwolt-backup, mailwolt-restore" # ───────────────────────────────────────────────────────────── # 6) systemd Service + Timer (Timer default via installer.env) # ───────────────────────────────────────────────────────────── cat > "${UNIT_DIR}/mailwolt-backup.service" <<'EOSVC' [Unit] Description=MailWolt Backup [Service] Type=oneshot ExecStart=/usr/local/sbin/mailwolt-backup Nice=10 IOSchedulingClass=best-effort IOSchedulingPriority=7 EOSVC cat > "${UNIT_DIR}/mailwolt-backup.timer" </dev/null 2>&1 || true fi log "[✓] Backup-Setup abgeschlossen."