mailwolt/scripts/update.sh

507 lines
20 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env bash
set -euo pipefail
# -------- Konfiguration -------------------------------------------------------
APP_USER="${APP_USER:-www-data}"
APP_GROUP="${APP_GROUP:-www-data}"
APP_DIR="${APP_DIR:-/var/www/mailwolt}"
BRANCH="${BRANCH:-main}"
MODE="${UPDATE_MODE:-tags}"
ALLOW_DIRTY="${ALLOW_DIRTY:-0}"
# -------- --check-only: nur Remote-Tags holen, Version schreiben, sicher beenden ---
# (wird von CheckUpdates via sudo aufgerufen — kein Update, nur Versionsprüfung)
if [[ "${1:-}" == "--check-only" ]]; then
LATEST="$(sudo -u "$APP_USER" bash -c \
"git -C '${APP_DIR}' ls-remote --tags --sort=-v:refname origin 'v*' 2>/dev/null \
| grep -v '\^{}' | head -1 | sed 's|.*refs/tags/||'" 2>/dev/null || true)"
if [[ -n "$LATEST" ]]; then
mkdir -p /var/lib/mailwolt
printf '%s\n' "$LATEST" > /var/lib/mailwolt/version_remote
fi
exit 0
fi
STATE_DIR="/var/lib/mailwolt/update"
LOCK_FILE="/var/run/mailwolt-update.lock"
LOG_FILE="/var/log/mailwolt-update.log"
# npm / CI Defaults
export CI=1
export NPM_CONFIG_FUND=false
export NPM_CONFIG_AUDIT=false
export npm_config_loglevel=warn
# -------- Helper --------------------------------------------------------------
as_app(){ sudo -u "$APP_USER" -H bash -lc "$*"; }
restart_if_exists(){
local u="$1"
systemctl list-unit-files | grep -q "^${u}\.service" && systemctl restart "$u" || true
}
reload_if_active(){
local u="$1"
systemctl is-active --quiet "$u" && systemctl reload "$u" || true
}
restart_php_fpm(){
for u in php8.3-fpm php8.2-fpm php8.1-fpm php-fpm; do
if systemctl list-unit-files | grep -q "^${u}\.service"; then
# reload = graceful: laufende Requests fertig, dann Workers tauschen
systemctl reload "$u" 2>/dev/null || systemctl restart "$u"
return 0
fi
done
}
artisan_down(){
as_app "cd ${APP_DIR} && php artisan down --render=errors.503 --retry=10" 2>/dev/null || true
echo "[i] Wartungsmodus aktiviert"
}
artisan_up(){
as_app "cd ${APP_DIR} && php artisan up" 2>/dev/null || true
echo "[i] Wartungsmodus beendet"
}
git_safe(){
# safe.directory system-weit (root → /etc/gitconfig → gilt für alle User)
git config --system --add safe.directory "${APP_DIR}" >/dev/null 2>&1 || true
# Gesamte App dem APP_USER zuweisen — root kann immer schreiben,
# aber PHP-FPM (www-data) braucht Lese-/Schreibrecht auf bootstrap/cache + storage
chown -R "${APP_USER}":"${APP_GROUP}" "${APP_DIR}" 2>/dev/null || true
}
git_dirty_check(){
# Als root ausführen: kein Permission-Problem unabhängig vom Dateieigentümer
local dirty
dirty="$(git -C "${APP_DIR}" status --porcelain 2>/dev/null || true)"
if [[ -n "$dirty" ]]; then
echo "[!] Uncommitted Änderungen — tracked Dateien werden zurückgesetzt:"
echo "$dirty"
git -C "${APP_DIR}" reset --hard HEAD 2>/dev/null || true
git -C "${APP_DIR}" clean -fd \
--exclude='.env' --exclude='storage/' --exclude='node_modules/' 2>/dev/null || true
fi
}
get_version(){
git -C "${APP_DIR}" describe --tags --always 2>/dev/null \
|| git -C "${APP_DIR}" rev-parse --short=7 HEAD 2>/dev/null \
|| echo "unknown"
}
write_version_files(){
local ver="$1" rev="$2"
install -d -m 0755 /etc/mailwolt /var/lib/mailwolt || true
printf "version=%s\nrev=%s\nupdated=%s\n" "$ver" "$rev" "$(date -Is)" > /etc/mailwolt/build.info || true
printf '%s\n' "${ver#v}" > /var/lib/mailwolt/version || true
printf '%s\n' "$ver" > /var/lib/mailwolt/version_raw || true
}
write_build_info(){ write_version_files "$@"; }
# --- Frontend build (quiet & robust) ------------------------------------------
frontend_build_quiet() {
local LOG="/var/log/mailwolt-frontend-build.log"
local NPM_ENV="CI=1 NPM_CONFIG_FUND=false NPM_CONFIG_AUDIT=false npm_config_loglevel=warn"
# Logfile vorbereiten
install -d -m 0755 "$(dirname "$LOG")"
: > "$LOG" || true
chmod 0644 "$LOG"
echo "[i] Frontend: vorbereiten …"
as_app "mkdir -p '${APP_DIR}/public/build' '${APP_DIR}/node_modules' '${APP_DIR}/.vite' '${APP_DIR}/.npm-cache'"
chown -R "$APP_USER":"$APP_GROUP" "${APP_DIR}/node_modules" "${APP_DIR}/.vite" "${APP_DIR}/.npm-cache" 2>/dev/null || true
# npm-Cache explizit im App-Verzeichnis setzen — verhindert Schreibfehler ins HOME
local NPM_CACHE_FLAG="--cache '${APP_DIR}/.npm-cache'"
# Altes Build-Verzeichnis sichern — wird erst nach erfolgreichem Build ersetzt
local BUILD_DIR="${APP_DIR}/public/build"
local BUILD_BAK="${APP_DIR}/public/build.bak"
rm -rf "${BUILD_BAK}" 2>/dev/null || true
[[ -d "${BUILD_DIR}" ]] && cp -a "${BUILD_DIR}" "${BUILD_BAK}" 2>/dev/null || true
rm -rf "${APP_DIR}/node_modules/.vite" "${BUILD_DIR}/"* 2>/dev/null || true
chown -R "$APP_USER":"$APP_GROUP" "${BUILD_DIR}" 2>/dev/null || true
as_app "printf 'fund=false\naudit=false\ncache=${APP_DIR}/.npm-cache\n' > ~/.npmrc" >>"$LOG" 2>&1 || true
echo "[i] Frontend: Dependencies … (Details: $LOG)"
if ! as_app "cd '${APP_DIR}' && ${NPM_ENV} npm ci --no-audit --no-fund --no-progress ${NPM_CACHE_FLAG}" >>"$LOG" 2>&1; then
if ! as_app "cd '${APP_DIR}' && ${NPM_ENV} npm install --no-audit --no-fund --no-progress ${NPM_CACHE_FLAG}" >>"$LOG" 2>&1; then
echo "[!] npm install fehlgeschlagen — altes Build wird wiederhergestellt."
[[ -d "${BUILD_BAK}" ]] && cp -a "${BUILD_BAK}/." "${BUILD_DIR}/" 2>/dev/null || true
tail -n 60 "$LOG" || true
return 1
fi
fi
echo "[i] Frontend: Build … (Details: $LOG)"
if ! as_app "cd '${APP_DIR}' && ${NPM_ENV} npm run build --silent --loglevel=warn ${NPM_CACHE_FLAG}" >>"$LOG" 2>&1; then
echo "[!] Build fehlgeschlagen — altes Build wird wiederhergestellt."
[[ -d "${BUILD_BAK}" ]] && cp -a "${BUILD_BAK}/." "${BUILD_DIR}/" 2>/dev/null || true
tail -n 80 "$LOG" || true
return 1
fi
rm -rf "${BUILD_BAK}" 2>/dev/null || true
chown -R "$APP_USER":"$APP_GROUP" "${BUILD_DIR}" || true
find "${BUILD_DIR}" -type d -exec chmod 2775 {} \; 2>/dev/null || true
find "${BUILD_DIR}" -type f -exec chmod 0664 {} \; 2>/dev/null || true
echo "[✓] Frontend gebaut."
}
# -------- Systemzustand sicherstellen (läuft bei JEDER Ausführung) -----------
# Neue Scripts/Sudoers-Regeln werden so auch ohne echtes Update eingespielt.
_sbin_install(){
local src="$1" dst="$2"
[[ -f "$src" ]] && install -m 755 "$src" "$dst" && return 0 || return 0
}
_sudoers_add(){
local file="$1" rule="$2"
[[ -f "$file" ]] || return 0
grep -qF "$rule" "$file" && return 0
chmod 640 "$file"
printf '%s\n' "$rule" >> "$file"
chmod 440 "$file"
}
fix_ownership(){
# Alle App-Dateien dem APP_USER zuweisen (git läuft als root → neue Dateien wären sonst root-owned)
# node_modules + vendor ausklammern (zu groß, werden separat behandelt)
for d in app bootstrap config database public resources routes scripts storage; do
[[ -e "${APP_DIR}/${d}" ]] && chown -R "${APP_USER}:${APP_GROUP}" "${APP_DIR}/${d}" 2>/dev/null || true
done
for f in artisan composer.json composer.lock package.json package-lock.json .env vite.config.js vite.config.ts; do
[[ -e "${APP_DIR}/${f}" ]] && chown "${APP_USER}:${APP_GROUP}" "${APP_DIR}/${f}" 2>/dev/null || true
done
chmod -R ug+rwX "${APP_DIR}/bootstrap/cache" "${APP_DIR}/storage" 2>/dev/null || true
find "${APP_DIR}/bootstrap/cache" "${APP_DIR}/storage" \
-type d -exec chmod g+s {} \; 2>/dev/null || true
}
fix_permissions(){
fix_ownership
# Frontend fehlt → rebuild
if [[ ! -f "${APP_DIR}/public/build/manifest.json" ]]; then
echo "[!] manifest.json fehlt — Frontend wird neu gebaut …"
frontend_build_quiet || true
fi
# Erst leeren, dann neu aufbauen — Permissions sind oben bereits korrekt gesetzt
sudo -u "${APP_USER}" php "${APP_DIR}/artisan" optimize:clear --quiet 2>/dev/null || true
sudo -u "${APP_USER}" php "${APP_DIR}/artisan" optimize --quiet 2>/dev/null || true
}
ensure_system(){
# Cache + Rechte immer korrigieren — auch wenn das sbin veraltet ist
fix_permissions
# Scripts nach sbin
_sbin_install "${APP_DIR}/scripts/mailwolt-apply-domains" /usr/local/sbin/mailwolt-apply-domains
_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
# 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/bin/openssl x509 -enddate -noout -in /etc/letsencrypt/live/*/fullchain.pem'
done
# Laravel Scheduler cron (schedule:run muss jede Minute laufen)
local cron_file="/etc/cron.d/mailwolt"
local cron_line="* * * * * www-data php ${APP_DIR}/artisan schedule:run >> /dev/null 2>&1"
if ! grep -qF "artisan schedule:run" "${cron_file}" 2>/dev/null; then
printf '%s\n' "${cron_line}" > "${cron_file}"
chmod 644 "${cron_file}"
echo "[✓] Laravel Scheduler cron installiert."
fi
# Reverb WebSocket Service
local ws_service="/etc/systemd/system/mailwolt-ws.service"
if [[ ! -f "${ws_service}" ]]; then
local php_bin
php_bin=$(command -v php || echo "/usr/bin/php")
cat > "${ws_service}" <<UNIT
[Unit]
Description=Laravel Reverb WebSocket (MailWolt)
After=network.target
[Service]
WorkingDirectory=${APP_DIR}
ExecStart=${php_bin} artisan reverb:start --host=127.0.0.1 --port=8080 --no-interaction
Restart=always
RestartSec=5
User=www-data
Group=www-data
KillSignal=SIGTERM
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable mailwolt-ws
systemctl start mailwolt-ws
echo "[✓] mailwolt-ws Service installiert und gestartet."
elif ! systemctl is-active --quiet mailwolt-ws; then
systemctl start mailwolt-ws
echo "[✓] mailwolt-ws Service gestartet."
fi
}
# -------- Guards --------------------------------------------------------------
[[ "$(id -u)" -eq 0 ]] || { echo "[!] Bitte als root ausführen"; exit 1; }
[[ -d "$APP_DIR/.git" ]] || { echo "[!] $APP_DIR scheint kein Git-Repo zu sein"; exit 1; }
# -------- Lock ----------------------------------------------------------------
mkdir -p "$STATE_DIR"
if [[ -f "$LOCK_FILE" ]]; then
LOCK_PID=$(cat "$LOCK_FILE" 2>/dev/null || true)
if [[ -n "$LOCK_PID" ]] && kill -0 "$LOCK_PID" 2>/dev/null; then
echo "[!] Update läuft bereits (PID $LOCK_PID) — Abbruch."
exit 1
fi
rm -f "$LOCK_FILE"
fi
echo $$ > "$LOCK_FILE"
# -------- State & Cleanup-Trap -----------------------------------------------
MAINTENANCE_ACTIVE=0
_cleanup() {
local rc=$?
[[ "$MAINTENANCE_ACTIVE" -eq 1 ]] && artisan_up
# Ownership immer korrigieren; Cache nur bei Fehler neu aufbauen
# (bei Erfolg hat fix_permissions im Hauptfluss bereits optimize gebaut)
if [[ $rc -ne 0 ]]; then
fix_permissions
else
fix_ownership
fi
mkdir -p "$STATE_DIR"
echo "done" > "$STATE_DIR/state"
echo "$rc" > "$STATE_DIR/rc"
rm -f "$LOCK_FILE"
}
trap '_cleanup' EXIT INT TERM
# Update als laufend markieren
echo "running" > "$STATE_DIR/state"
rm -f "$STATE_DIR/rc"
: > "$LOG_FILE"
# Alle echo-Ausgaben in Log-Datei schreiben (und stdout — für CLI-Nutzung)
exec > >(tee -a "$LOG_FILE") 2>&1
git_safe
git_dirty_check
# -------- Git: neuen Stand holen ---------------------------------------------
echo "[i] Prüfe Repository …"
OLD_REV="$(git -C "${APP_DIR}" rev-parse HEAD)"
OLD_VER="$(get_version)"
NEW_REV="$OLD_REV"
if [[ "$MODE" = "tags" ]]; then
# Tags vom Remote holen (als root — hat Zugriff auf gespeicherte Credentials)
git -C "${APP_DIR}" fetch --quiet origin 2>/dev/null || true
git -C "${APP_DIR}" fetch --tags --quiet origin 2>/dev/null || true
LATEST_TAG="$(git -C "${APP_DIR}" describe --tags --abbrev=0 \
"$(git -C "${APP_DIR}" rev-list --tags --max-count=1 2>/dev/null)" 2>/dev/null || echo '')"
# Neuesten Remote-Tag cachen
[[ -n "$LATEST_TAG" ]] && { mkdir -p /var/lib/mailwolt; printf '%s\n' "$LATEST_TAG" > /var/lib/mailwolt/version_remote; } || true
if [[ -z "$LATEST_TAG" ]]; then
echo "[!] Keine Tags gefunden falle auf origin/${BRANCH} zurück"
git -C "${APP_DIR}" checkout -q "${BRANCH}"
git -C "${APP_DIR}" pull --ff-only origin "${BRANCH}"
else
TARGET_REV="$(git -C "${APP_DIR}" rev-list -n1 "${LATEST_TAG}")"
if [[ "$TARGET_REV" = "$OLD_REV" ]]; then
echo "[✓] Bereits auf neuestem Release (${LATEST_TAG}) nichts zu tun."
write_build_info "$(get_version)" "$OLD_REV"
ensure_system
exit 0
fi
echo "[i] Checkout auf Release ${LATEST_TAG} (${TARGET_REV:0:7}) …"
git -C "${APP_DIR}" checkout -q "${LATEST_TAG}"
fi
NEW_REV="$(git -C "${APP_DIR}" rev-parse HEAD)"
# Nach Checkout Eigentümer korrigieren
chown -R "${APP_USER}":"${APP_GROUP}" "${APP_DIR}" 2>/dev/null || true
else
# Rolling: branch folgen
git -C "${APP_DIR}" fetch --quiet origin "${BRANCH}" 2>/dev/null || true
BEHIND="$(git -C "${APP_DIR}" rev-list --count "HEAD..origin/${BRANCH}" 2>/dev/null || echo 0)"
if [[ "$BEHIND" -eq 0 ]]; then
echo "[✓] Branch origin/${BRANCH} ist bereits aktuell nichts zu tun."
write_build_info "$(get_version)" "$OLD_REV"
ensure_system
exit 0
fi
echo "[i] Es gibt ${BEHIND} neue Commit(s) ziehe Änderungen …"
git -C "${APP_DIR}" checkout -q "${BRANCH}"
git -C "${APP_DIR}" pull --ff-only origin "${BRANCH}"
NEW_REV="$(git -C "${APP_DIR}" rev-parse HEAD)"
chown -R "${APP_USER}":"${APP_GROUP}" "${APP_DIR}" 2>/dev/null || true
fi
# -------- Änderungstypen ermitteln -------------------------------------------
CHANGED_FILES="$(as_app "git -C ${APP_DIR} diff --name-only ${OLD_REV}..${NEW_REV}")"
NEED_COMPOSER=0
NEED_MIGRATIONS=0
NEED_FRONTEND=0
NEED_PHP_RESTART=0
NEED_SBIN_UPDATE=0
echo "$CHANGED_FILES" | grep -qE '(^|/)composer\.(json|lock)$' && NEED_COMPOSER=1
echo "$CHANGED_FILES" | grep -qE '^database/migrations/' && NEED_MIGRATIONS=1
echo "$CHANGED_FILES" | grep -qE '^(package(-lock)?\.json|vite\.config(\.ts|\.js)?|resources/|public/.*\.(js|css))' && NEED_FRONTEND=1
echo "$CHANGED_FILES" | grep -qE '^(app/|routes/|config/|resources/views/)' && NEED_PHP_RESTART=1
echo "$CHANGED_FILES" | grep -qE '^scripts/' && NEED_SBIN_UPDATE=1
echo "[i] Zusammenfassung:"
echo " Composer : $([[ $NEED_COMPOSER -eq 1 ]] && echo JA || echo nein)"
echo " Migrations : $([[ $NEED_MIGRATIONS -eq 1 ]] && echo JA || echo nein)"
echo " Frontend : $([[ $NEED_FRONTEND -eq 1 ]] && echo JA || echo nein)"
echo " PHP restart : $([[ $NEED_PHP_RESTART -eq 1 ]] && echo JA || echo nein)"
echo " Sbin-Scripts : $([[ $NEED_SBIN_UPDATE -eq 1 ]] && echo JA || echo nein)"
# System-Scripts aus scripts/ sofort nach dem Pull einspielen (kein Downtime nötig)
# ensure_system() am Ende des Scripts übernimmt das vollständig.
# .env immer migrieren (unabhängig vom Update-Pfad)
as_app "cd ${APP_DIR} && php artisan mailwolt:migrate-env-reverb" 2>/dev/null || migrate_env_reverb
# Wenn gar nichts relevantes geändert wurde → sauber beenden
if [[ $NEED_COMPOSER -eq 0 && $NEED_MIGRATIONS -eq 0 && $NEED_FRONTEND -eq 0 && $NEED_PHP_RESTART -eq 0 ]]; then
echo "[✓] Code-Stand aktualisiert, aber keine Build/Runtime-Änderungen keine Neustarts nötig."
NEW_VER="$(get_version)"
write_build_info "$NEW_VER" "$NEW_REV"
echo "[i] Version: ${OLD_VER}${NEW_VER}"
fix_permissions
ensure_system
exit 0
fi
# -------- Composer (ohne Downtime) -------------------------------------------
if [[ $NEED_COMPOSER -eq 1 ]]; then
echo "[i] Composer …"
as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev"
fi
# -------- Frontend (ohne Downtime — Assets sind statisch) --------------------
if [[ $NEED_FRONTEND -eq 1 ]]; then
echo "[i] Frontend-Änderungen erkannt baue Assets …"
if ! frontend_build_quiet; then
echo "[!] Frontend-Build ist fehlgeschlagen (siehe /var/log/mailwolt-frontend-build.log)."
exit 1
fi
fi
# -------- Wartungsmodus: Migrations + Cache + PHP-FPM reload -----------------
if [[ $NEED_MIGRATIONS -eq 1 || $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 ]]; then
artisan_down
MAINTENANCE_ACTIVE=1
fi
if [[ $NEED_MIGRATIONS -eq 1 ]]; then
echo "[i] DB-Migrationen …"
as_app "cd ${APP_DIR} && php artisan migrate --force"
fi
if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
as_app "cd ${APP_DIR} && php artisan queue:restart || true"
fi
# -------- Version + Build-Info ablegen ----------------------------------------
NEW_VER="$(get_version)"
write_version_files "$NEW_VER" "$NEW_REV"
# -------- Rechte + Cache aufbauen (VOR PHP-FPM Restart) ----------------------
# fix_permissions: chown aller App-Dirs + optimize:clear + optimize
# PHP-FPM startet erst danach → kein Request trifft kaputte/leere Caches
fix_permissions
# -------- Dienste neu laden (gezielt) ----------------------------------------
echo "[i] Dienste neu laden …"
if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
restart_php_fpm
restart_if_exists "${APP_USER}-queue"
restart_if_exists "${APP_USER}-schedule"
restart_if_exists "${APP_USER}-ws"
fi
if [[ $NEED_FRONTEND -eq 1 || $NEED_PHP_RESTART -eq 1 ]]; then
reload_if_active nginx
fi
# -------- Wartungsmodus beenden ----------------------------------------------
if [[ "$MAINTENANCE_ACTIVE" -eq 1 ]]; then
artisan_up
MAINTENANCE_ACTIVE=0
fi
echo "[✓] Update abgeschlossen: ${OLD_VER}${NEW_VER} (${OLD_REV:0:7}${NEW_REV:0:7})"
# -------- .env: REVERB-Werte auf Domain-Basis normalisieren -------------------
migrate_env_reverb() {
local env_file="${APP_DIR}/.env"
[ -f "${env_file}" ] || return 0
# APP_HOST auslesen — Fallback auf APP_URL wenn nicht gesetzt
local app_host
app_host=$(grep '^APP_HOST=' "${env_file}" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")
if [ -z "${app_host}" ]; then
local app_url
app_url=$(grep '^APP_URL=' "${env_file}" | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'")
# https://domain.at → domain.at oder http://1.2.3.4 → 1.2.3.4
app_host=$(echo "${app_url}" | sed 's|https\?://||' | cut -d/ -f1 | cut -d: -f1)
fi
[ -z "${app_host}" ] && return 0
# IP-Adresse → nichts tun (kein sinnvoller Hostname für TLS)
echo "${app_host}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' && return 0
# Nur migrieren wenn VITE_REVERB_HOST nicht auf app_host zeigt
local current_vite_host
current_vite_host=$(grep '^VITE_REVERB_HOST=' "${env_file}" | head -1 | cut -d= -f2-)
if [ "${current_vite_host}" = "\${REVERB_HOST}" ] || [ "${current_vite_host}" = "${app_host}" ]; then
return 0 # bereits korrekt
fi
echo "[i] .env: REVERB-Werte werden auf Domain '${app_host}' aktualisiert …"
local scheme="http" port="80"
[ -f "/etc/letsencrypt/live/${app_host}/fullchain.pem" ] && scheme="https" && port="443"
_uenv() {
local k="$1" v="$2"
if grep -q "^${k}=" "${env_file}"; then
sed -i "s|^${k}=.*|${k}=${v}|" "${env_file}"
else
echo "${k}=${v}" >> "${env_file}"
fi
}
_uenv "REVERB_HOST" "\${APP_HOST}"
_uenv "REVERB_PORT" "${port}"
_uenv "REVERB_SCHEME" "${scheme}"
_uenv "REVERB_PATH" "/ws"
_uenv "REVERB_SERVER_HOST" "127.0.0.1"
_uenv "REVERB_SERVER_PORT" "8080"
_uenv "REVERB_SERVER_SCHEME" "http"
_uenv "REVERB_SERVER_PATH" ""
_uenv "VITE_REVERB_HOST" "\${REVERB_HOST}"
_uenv "VITE_REVERB_PORT" "\${REVERB_PORT}"
_uenv "VITE_REVERB_SCHEME" "\${REVERB_SCHEME}"
_uenv "VITE_REVERB_PATH" "\${REVERB_PATH}"
# Assets neu bauen mit den korrekten Werten
frontend_build_quiet || true
as_app "cd ${APP_DIR} && php artisan optimize:clear || true"
echo "[✓] REVERB .env migriert + Assets neu gebaut."
}
migrate_env_reverb
ensure_system