Fix: SSL-Cert-Status zeigt 'Fehlt' obwohl Cert vorhanden

Problem: /etc/letsencrypt/archive/ ist chmod 700 (root only).
file_exists() auf Symlinks in live/ schlägt fehl weil Symlink-Ziel
in archive/ nicht lesbar ist. is_dir() auf live/domain/ funktioniert
da das Verzeichnis selbst 755 ist.

- SettingsForm: file_exists() → is_dir() für Existenzcheck
- SettingsForm: openssl-Aufruf via sudo -n (archive/ ist root-only)
- installer.sh + update.sh: sudoers-Regel für openssl auf LE-Cert-Pfade
  (www-data darf nur exakt diesen openssl-Aufruf, keine anderen Pfade)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main v1.1.273
boban 2026-04-26 08:27:49 +02:00
parent 880b99f1e0
commit 096e983313
3 changed files with 20 additions and 7 deletions

View File

@ -296,12 +296,16 @@ class SettingsForm extends Component
$certs[$key] = ['domain' => '', 'has_cert' => false, 'expiry' => null, 'status' => 'nodomain'];
continue;
}
$certFile = "/etc/letsencrypt/live/{$domain}/fullchain.pem";
if (! file_exists($certFile)) {
$certDir = "/etc/letsencrypt/live/{$domain}";
$certFile = "{$certDir}/fullchain.pem";
// live/ ist 755 (traversierbar), archive/ ist 700 — file_exists() schlägt fehl
// weil der Symlink auf archive/ zeigt. is_dir() auf live/domain/ funktioniert.
if (! is_dir($certDir)) {
$certs[$key] = ['domain' => $domain, 'has_cert' => false, 'expiry' => null, 'status' => 'missing'];
continue;
}
$expiry = trim((string) @shell_exec("openssl x509 -enddate -noout -in " . escapeshellarg($certFile) . " 2>/dev/null | sed 's/notAfter=//'"));
// sudo nötig weil archive/ (Symlink-Ziel) nur root lesbar ist
$expiry = trim((string) @shell_exec("sudo -n openssl x509 -enddate -noout -in " . escapeshellarg($certFile) . " 2>/dev/null | sed 's/notAfter=//'"));
$expiryTs = $expiry ? strtotime($expiry) : null;
$daysLeft = $expiryTs ? (int) round(($expiryTs - time()) / 86400) : null;
$certStatus = match (true) {

View File

@ -591,6 +591,7 @@ www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-apply-domains
www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-fetch-tags
www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-update
www-data ALL=(root) NOPASSWD: /usr/bin/certbot
www-data ALL=(root) NOPASSWD: /usr/bin/openssl x509 -enddate -noout -in /etc/letsencrypt/live/*/fullchain.pem
SUDOERS
chmod 440 /etc/sudoers.d/mailwolt-certbot

View File

@ -324,7 +324,15 @@ echo "[✓] Update abgeschlossen: ${OLD_VER} → ${NEW_VER} (${OLD_REV:0:7} →
install -m 755 "${APP_DIR}/scripts/mailwolt-fetch-tags" /usr/local/sbin/mailwolt-fetch-tags
install -m 755 "${APP_DIR}/scripts/update.sh" /usr/local/sbin/mailwolt-update
# Sudoers: sicherstellen dass mailwolt-fetch-tags eingetragen ist (Upgrade-Pfad für bestehende Instanzen)
if [[ -f /etc/sudoers.d/mailwolt-certbot ]] && ! grep -q 'mailwolt-fetch-tags' /etc/sudoers.d/mailwolt-certbot; then
echo 'www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-fetch-tags' >> /etc/sudoers.d/mailwolt-certbot
# Sudoers: fehlende Einträge nachrüsten (Upgrade-Pfad für bestehende Instanzen)
_sudoers_add() {
local file="$1" rule="$2"
if [[ -f "$file" ]] && ! grep -qF "$rule" "$file"; then
chmod 640 "$file"
echo "$rule" >> "$file"
chmod 440 "$file"
fi
}
_sudoers_add /etc/sudoers.d/mailwolt-certbot 'www-data ALL=(root) NOPASSWD: /usr/local/sbin/mailwolt-fetch-tags'
_sudoers_add /etc/sudoers.d/mailwolt-certbot 'www-data ALL=(root) NOPASSWD: /usr/bin/openssl x509 -enddate -noout -in /etc/letsencrypt/live/*/fullchain.pem'
_sudoers_add /etc/sudoers.d/mailwolt-dkim 'www-data ALL=(root) NOPASSWD: /usr/bin/openssl x509 -enddate -noout -in /etc/letsencrypt/live/*/fullchain.pem'