Fix: Backup läuft als root via sudo – keine Permission-Fehler mehr

mailwolt-backup Script liest /etc/dovecot/private, /etc/letsencrypt/live
etc. als root. ensure_system() installiert es nach sbin + sudoers.
BackupRun.php ruft es via sudo -n auf.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main v1.1.346
boban 2026-04-26 21:37:27 +02:00
parent 7e7d5c1069
commit de314adebe
3 changed files with 72 additions and 1 deletions

View File

@ -28,7 +28,7 @@ class BackupRun extends Command
$script = '/usr/local/sbin/mailwolt-backup';
if (file_exists($script)) {
$output = [];
exec("bash " . escapeshellarg($script) . ' 2>&1', $output, $exitCode);
exec('sudo -n ' . escapeshellarg($script) . ' 2>&1', $output, $exitCode);
$artifact = null;
foreach ($output as $line) {

69
scripts/mailwolt-backup Normal file
View File

@ -0,0 +1,69 @@
#!/usr/bin/env bash
# Mailwolt Backup läuft als root via sudo, liest DB-Credentials aus .env
set -euo pipefail
APP_DIR="/var/www/mailwolt"
APP_USER="www-data"
OUT_DIR="${APP_DIR}/storage/app/backups"
STAMP="$(date +%Y-%m-%d_%H-%M-%S)"
OUT_FILE="${OUT_DIR}/mailwolt_${STAMP}.tar.gz"
TMP_DIR="$(mktemp -d /tmp/mailwolt_backup_XXXXXX)"
cleanup(){ rm -rf "$TMP_DIR"; }
trap cleanup EXIT
mkdir -p "$OUT_DIR"
chown "${APP_USER}:${APP_USER}" "$OUT_DIR" 2>/dev/null || true
# ── Datenbank ──────────────────────────────────────────────────────────────
ENV_FILE="${APP_DIR}/.env"
DB_HOST="127.0.0.1"; DB_PORT="3306"; DB_USER=""; DB_PASS=""; DB_NAME=""
if [[ -f "$ENV_FILE" ]]; then
DB_HOST="$(grep '^DB_HOST=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
DB_PORT="$(grep '^DB_PORT=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
DB_USER="$(grep '^DB_USERNAME=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
DB_PASS="$(grep '^DB_PASSWORD=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
DB_NAME="$(grep '^DB_DATABASE=' "$ENV_FILE" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")"
fi
DUMP_FILE="${TMP_DIR}/database.sql"
if [[ -n "$DB_NAME" ]]; then
MYSQL_PWD="$DB_PASS" mysqldump \
-h "${DB_HOST:-127.0.0.1}" -P "${DB_PORT:-3306}" \
-u "$DB_USER" \
--single-transaction --routines --triggers \
"$DB_NAME" > "$DUMP_FILE" 2>&1
echo "✓ Datenbank gesichert"
else
echo "✗ DB_DATABASE nicht in .env gefunden"
fi
# ── Quellen sammeln ────────────────────────────────────────────────────────
SOURCES=("$DUMP_FILE")
for MAIL_DIR in /var/vmail /var/mail/vhosts /home/vmail; do
if [[ -d "$MAIL_DIR" ]]; then
SOURCES+=("$MAIL_DIR")
echo "✓ Maildirs: $MAIL_DIR"
break
fi
done
for CFG_DIR in /etc/postfix /etc/dovecot /etc/opendkim /etc/rspamd /etc/letsencrypt; do
if [[ -d "$CFG_DIR" ]]; then
SOURCES+=("$CFG_DIR")
echo "✓ $CFG_DIR"
fi
done
if [[ -f "${APP_DIR}/.env" ]]; then
SOURCES+=("${APP_DIR}/.env")
echo "✓ .env"
fi
# ── Archiv erstellen ───────────────────────────────────────────────────────
tar --ignore-failed-read -czf "$OUT_FILE" "${SOURCES[@]}" 2>&1 || true
chown "${APP_USER}:${APP_USER}" "$OUT_FILE" 2>/dev/null || true
echo "ARTIFACT:${OUT_FILE}"

View File

@ -206,11 +206,13 @@ ensure_system(){
_sbin_install "${APP_DIR}/scripts/mailwolt-fetch-tags" /usr/local/sbin/mailwolt-fetch-tags
_sbin_install "${APP_DIR}/scripts/update.sh" /usr/local/sbin/mailwolt-update
_sbin_install "${APP_DIR}/scripts/mailwolt-clamav" /usr/local/sbin/mailwolt-clamav
_sbin_install "${APP_DIR}/scripts/mailwolt-backup" /usr/local/sbin/mailwolt-backup
# Sudoers-Regeln nachrüsten
for f in /etc/sudoers.d/mailwolt-certbot /etc/sudoers.d/mailwolt-dkim; do
_sudoers_add "$f" 'www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-fetch-tags'
_sudoers_add "$f" 'www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-update --check-only'
_sudoers_add "$f" 'www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-clamav'
_sudoers_add "$f" 'www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-backup'
_sudoers_add "$f" 'www-data ALL=(root) NOPASSWD: /usr/bin/openssl x509 -enddate -noout -in /etc/letsencrypt/live/*/fullchain.pem'
done
# Laravel Scheduler cron (schedule:run muss jede Minute laufen)