Compare commits

...

3 Commits

Author SHA1 Message Date
boban d50aedeafb Fix: nginx http2 Syntax für nginx 1.25+ (listen 443 ssl + http2 on)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:16:20 +02:00
boban bc2810eb8a Fix: certbot in sudoers + SSL-Seite zeigt Zertifikate
www-data braucht sudo-Recht auf certbot für SSL-Seite (certificates/renew)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:29:57 +02:00
boban 894f753b81 Fix: Wizard SSL-Flow end-to-end sauber gelöst
- pollSetup() macht keinen auto-redirect mehr (port 443 wäre noch nicht offen)
- "Zum Login" ist jetzt ein plain <a href="/login"> ohne Livewire-POST
  → nginx leitet /login nach SSL-Switch automatisch auf HTTPS weiter
- mailwolt-apply-domains schreibt done=1/0 (je nach Cert-Status) VOR nginx-Switch
  + sleep 6s damit Polling noch 3x done lesen kann bevor port 443 öffnet
- done=1 nur wenn mindestens ein LE-Cert erfolgreich ausgestellt wurde

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:11:50 +02:00
3 changed files with 20 additions and 16 deletions

View File

@ -181,12 +181,6 @@ class Wizard extends Component
$done = @file_get_contents(self::STATE_DIR . '/done'); $done = @file_get_contents(self::STATE_DIR . '/done');
if ($done !== false) { if ($done !== false) {
$this->setupDone = true; $this->setupDone = true;
// Bei erfolgreichem SSL sofort auf HTTPS weiterleiten,
// damit Livewire nicht mehr über HTTP pollt
if (trim($done) === '1' && $this->ui_domain) {
$this->redirect('https://' . $this->ui_domain . '/setup', navigate: false);
}
} }
} }

View File

@ -725,8 +725,9 @@ if [ -n "${UI_HOST}" ] && [ "${UI_HAS_CERT}" = "1" ]; then
cat <<CONF cat <<CONF
server { server {
listen 443 ssl http2; listen 443 ssl;
listen [::]:443 ssl http2; listen [::]:443 ssl;
http2 on;
server_name ${UI_HOST}; server_name ${UI_HOST};
ssl_certificate /etc/letsencrypt/live/${UI_HOST}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${UI_HOST}/fullchain.pem;
@ -752,8 +753,9 @@ if [ -n "${WEBMAIL_HOST}" ] && [ "${WM_HAS_CERT}" = "1" ]; then
cat <<CONF cat <<CONF
server { server {
listen 443 ssl http2; listen 443 ssl;
listen [::]:443 ssl http2; listen [::]:443 ssl;
http2 on;
server_name ${WEBMAIL_HOST}; server_name ${WEBMAIL_HOST};
ssl_certificate /etc/letsencrypt/live/${WEBMAIL_HOST}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${WEBMAIL_HOST}/fullchain.pem;
@ -776,15 +778,20 @@ CONF
fi fi
) > "${NGINX_SITE}" ) > "${NGINX_SITE}"
# State-Dateien VOR dem nginx-Switch schreiben damit der Browser # State-Dateien VOR dem nginx-Switch schreiben:
# noch über HTTP redirecten kann bevor nginx auf HTTPS wechselt # Browser-Poll (alle 2s) liest done=1 → Polling stoppt → "Zum Login" erscheint.
# Danach 6s sleep → nginx switchet auf HTTPS → User klickt Link → funktioniert.
STATE_DIR="/var/lib/mailwolt/wizard" STATE_DIR="/var/lib/mailwolt/wizard"
if [ -d "${STATE_DIR}" ]; then if [ -d "${STATE_DIR}" ]; then
for k in ui mail webmail; do for k in ui mail webmail; do
[ -f "${STATE_DIR}/${k}" ] && printf "done" > "${STATE_DIR}/${k}" [ -f "${STATE_DIR}/${k}" ] && printf "done" > "${STATE_DIR}/${k}"
done done
if [ "${UI_HAS_CERT}" = "1" ] || [ "${WM_HAS_CERT}" = "1" ]; then
printf "1" > "${STATE_DIR}/done" printf "1" > "${STATE_DIR}/done"
sleep 6 # 3 Poll-Zyklen (à 2s) — Browser hat Zeit zu redirecten else
printf "0" > "${STATE_DIR}/done"
fi
sleep 6
fi fi
nginx -t && systemctl reload nginx nginx -t && systemctl reload nginx
@ -798,6 +805,7 @@ install -m 755 "${APP_DIR}/update.sh" /usr/local/sbin/mailwolt-update
cat > /etc/sudoers.d/mailwolt-certbot <<'SUDOERS' cat > /etc/sudoers.d/mailwolt-certbot <<'SUDOERS'
www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-apply-domains www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-apply-domains
www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-update www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-update
www-data ALL=(root) NOPASSWD: /usr/bin/certbot
SUDOERS SUDOERS
chmod 440 /etc/sudoers.d/mailwolt-certbot chmod 440 /etc/sudoers.d/mailwolt-certbot

View File

@ -292,10 +292,12 @@
</div> </div>
@elseif($step === 5 && $setupDone) @elseif($step === 5 && $setupDone)
<div style="display:flex;justify-content:flex-end;margin-top:20px"> <div style="display:flex;justify-content:flex-end;margin-top:20px">
<button wire:click="goToLogin" class="mbx-btn-primary" style="font-size:12.5px;width:fit-content"> {{-- Kein wire:click plain Link damit kein Livewire-POST nötig ist.
nginx leitet /login nach SSL-Switch automatisch auf HTTPS weiter. --}}
<a href="/login" class="mbx-btn-primary" style="font-size:12.5px;width:fit-content;text-decoration:none;display:inline-flex;align-items:center;gap:6px">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M2 6.5l2.5 2.5 5.5-5.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg> <svg width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M2 6.5l2.5 2.5 5.5-5.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
{{ collect($domainStatus)->contains(fn($s) => in_array($s, ['error','nodns','noipv6'])) ? 'Trotzdem zum Login' : 'Zum Login' }} {{ collect($domainStatus)->contains(fn($s) => in_array($s, ['error','nodns','noipv6'])) ? 'Trotzdem zum Login' : 'Zum Login' }}
</button> </a>
</div> </div>
@endif @endif