Dovecot Systax Problem
parent
06263461a3
commit
4b9a142712
|
|
@ -12,11 +12,10 @@ apt-get update -y
|
||||||
apt-get -y -o Dpkg::Options::="--force-confdef" \
|
apt-get -y -o Dpkg::Options::="--force-confdef" \
|
||||||
-o Dpkg::Options::="--force-confold" install \
|
-o Dpkg::Options::="--force-confold" install \
|
||||||
postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql \
|
postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql \
|
||||||
mariadb-server mariadb-client redis-server \
|
mariadb-server mariadb-client redis-server rspamd opendkim opendkim-tools opendmarc clamav \
|
||||||
rspamd opendkim opendkim-tools \
|
clamav-daemon nginx php php-fpm php-cli php-mbstring php-xml php-curl php-zip php-mysql \
|
||||||
nginx php php-fpm php-cli php-mbstring php-xml php-curl php-zip php-mysql php-redis php-gd \
|
php-redis php-gd unzip curl composer git certbot python3-certbot-nginx fail2ban ca-certificates \
|
||||||
unzip curl composer git certbot python3-certbot-nginx \
|
rsyslog sudo openssl monit acl netcat-openbsd
|
||||||
ca-certificates rsyslog sudo openssl monit acl netcat-openbsd
|
|
||||||
|
|
||||||
# <<< Apache konsequent entfernen >>>
|
# <<< Apache konsequent entfernen >>>
|
||||||
systemctl disable --now apache2 >/dev/null 2>&1 || true
|
systemctl disable --now apache2 >/dev/null 2>&1 || true
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,29 @@ fi
|
||||||
/usr/sbin/postconf -e "smtp_tls_security_level = may"
|
/usr/sbin/postconf -e "smtp_tls_security_level = may"
|
||||||
/usr/sbin/postconf -e "smtp_tls_loglevel = 1"
|
/usr/sbin/postconf -e "smtp_tls_loglevel = 1"
|
||||||
|
|
||||||
|
# ++ HÄRTUNG: DH-Parameter + ECDHE bevorzugen ++
|
||||||
|
DH_FILE="/etc/ssl/private/dhparams.pem"
|
||||||
|
if [[ ! -s "$DH_FILE" ]]; then
|
||||||
|
openssl dhparam -out "$DH_FILE" 4096
|
||||||
|
chmod 600 "$DH_FILE"
|
||||||
|
chown root:root "$DH_FILE"
|
||||||
|
fi
|
||||||
|
/usr/sbin/postconf -e "smtpd_tls_dh1024_param_file = ${DH_FILE}"
|
||||||
|
/usr/sbin/postconf -e "smtpd_tls_eecdh_grade = strong"
|
||||||
|
/usr/sbin/postconf -e "tls_preempt_cipherlist = yes"
|
||||||
|
|
||||||
|
# Nur moderne TLS-Versionen (auch für ausgehendes SMTP)
|
||||||
|
# (überschreibt die älteren Zeilen oben)
|
||||||
|
/usr/sbin/postconf -e "smtpd_tls_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1"
|
||||||
|
/usr/sbin/postconf -e "smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1"
|
||||||
|
/usr/sbin/postconf -e "smtp_tls_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1"
|
||||||
|
|
||||||
|
# Hohe Cipher, alte raus
|
||||||
|
/usr/sbin/postconf -e "smtpd_tls_ciphers = high"
|
||||||
|
/usr/sbin/postconf -e "smtp_tls_ciphers = high"
|
||||||
|
/usr/sbin/postconf -e "smtpd_tls_exclude_ciphers = aNULL,eNULL,MD5,RC4,DES,3DES"
|
||||||
|
/usr/sbin/postconf -e "smtp_tls_exclude_ciphers = aNULL,eNULL,MD5,RC4,DES,3DES"
|
||||||
|
|
||||||
# --- SMTP Sicherheit ----------------------------------------------------------
|
# --- SMTP Sicherheit ----------------------------------------------------------
|
||||||
/usr/sbin/postconf -e "disable_vrfy_command = yes"
|
/usr/sbin/postconf -e "disable_vrfy_command = yes"
|
||||||
/usr/sbin/postconf -e "smtpd_helo_required = yes"
|
/usr/sbin/postconf -e "smtpd_helo_required = yes"
|
||||||
|
|
@ -106,4 +129,4 @@ chmod 640 /etc/postfix/sql/mysql-virtual-alias-maps.cf
|
||||||
/usr/sbin/postconf -e "virtual_transport = lmtp:unix:private/dovecot-lmtp"
|
/usr/sbin/postconf -e "virtual_transport = lmtp:unix:private/dovecot-lmtp"
|
||||||
|
|
||||||
# --- Dienst aktivieren & neu laden --------------------------------------------
|
# --- Dienst aktivieren & neu laden --------------------------------------------
|
||||||
systemctl enable postfix >/dev/null 2>&1 || true
|
#systemctl enable postfix >/dev/null 2>&1 || true
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,10 @@ else
|
||||||
fi
|
fi
|
||||||
grep -q '^ssl_min_protocol' "$DOVECOT_SSL_CONF" || echo "ssl_min_protocol = TLSv1.2" >> "$DOVECOT_SSL_CONF"
|
grep -q '^ssl_min_protocol' "$DOVECOT_SSL_CONF" || echo "ssl_min_protocol = TLSv1.2" >> "$DOVECOT_SSL_CONF"
|
||||||
|
|
||||||
|
# Starke Cipher + DH-Params für DHE-Fallback
|
||||||
|
grep -q '^ssl_prefer_server_ciphers' "$DOVECOT_SSL_CONF" || echo "ssl_prefer_server_ciphers = yes" >> "$DOVECOT_SSL_CONF"
|
||||||
|
grep -q '^ssl_dh' "$DOVECOT_SSL_CONF" || echo "ssl_dh = </etc/ssl/private/dhparams.pem" >> "$DOVECOT_SSL_CONF"
|
||||||
|
|
||||||
# Postfix-Socket-Verzeichnis sicherstellen
|
# Postfix-Socket-Verzeichnis sicherstellen
|
||||||
mkdir -p /var/spool/postfix/private
|
mkdir -p /var/spool/postfix/private
|
||||||
chown root:root /var/spool/postfix
|
chown root:root /var/spool/postfix
|
||||||
|
|
@ -176,124 +180,4 @@ chown postfix:postfix /var/spool/postfix/private
|
||||||
chmod 0755 /var/spool/postfix/private
|
chmod 0755 /var/spool/postfix/private
|
||||||
|
|
||||||
# Nur aktivieren – Start/Reload später
|
# Nur aktivieren – Start/Reload später
|
||||||
systemctl enable dovecot >/dev/null 2>&1 || true
|
|
||||||
|
|
||||||
##!/usr/bin/env bash
|
|
||||||
#set -euo pipefail
|
|
||||||
#source ./lib.sh
|
|
||||||
#
|
|
||||||
#MAIL_SSL_DIR="/etc/ssl/mail"
|
|
||||||
#MAIL_CERT="${MAIL_SSL_DIR}/fullchain.pem"
|
|
||||||
#MAIL_KEY="${MAIL_SSL_DIR}/privkey.pem"
|
|
||||||
#
|
|
||||||
#log "Dovecot konfigurieren …"
|
|
||||||
#
|
|
||||||
## Hauptdatei
|
|
||||||
#cat > /etc/dovecot/dovecot.conf <<'CONF'
|
|
||||||
#!include_try /etc/dovecot/conf.d/*.conf
|
|
||||||
#CONF
|
|
||||||
#
|
|
||||||
## Mail-Location & Namespace
|
|
||||||
#cat > /etc/dovecot/conf.d/10-mail.conf <<'CONF'
|
|
||||||
#protocols = imap pop3 lmtp
|
|
||||||
#mail_location = maildir:/var/mail/vhosts/%d/%n
|
|
||||||
#
|
|
||||||
#namespace inbox {
|
|
||||||
# inbox = yes
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
#mail_privileged_group = mail
|
|
||||||
#first_valid_uid = 109
|
|
||||||
#last_valid_uid = 109
|
|
||||||
#CONF
|
|
||||||
#
|
|
||||||
## Auth
|
|
||||||
#cat > /etc/dovecot/conf.d/10-auth.conf <<'CONF'
|
|
||||||
#disable_plaintext_auth = yes
|
|
||||||
#auth_mechanisms = plain login
|
|
||||||
#!include_try auth-sql.conf.ext
|
|
||||||
#CONF
|
|
||||||
#
|
|
||||||
## SQL-Anbindung
|
|
||||||
#cat > /etc/dovecot/dovecot-sql.conf.ext <<CONF
|
|
||||||
#driver = mysql
|
|
||||||
#connect = host=127.0.0.1 dbname=${DB_NAME} user=${DB_USER} password=${DB_PASS}
|
|
||||||
#default_pass_scheme = BLF-CRYPT
|
|
||||||
#password_query = SELECT email AS user, password_hash AS password FROM mail_users WHERE email = '%u' AND is_active = 1 LIMIT 1;
|
|
||||||
#CONF
|
|
||||||
#chown root:dovecot /etc/dovecot/dovecot-sql.conf.ext
|
|
||||||
#chmod 640 /etc/dovecot/dovecot-sql.conf.ext
|
|
||||||
#
|
|
||||||
## Auth-SQL Einbindung
|
|
||||||
#cat > /etc/dovecot/conf.d/auth-sql.conf.ext <<'CONF'
|
|
||||||
#passdb {
|
|
||||||
# driver = sql
|
|
||||||
# args = /etc/dovecot/dovecot-sql.conf.ext
|
|
||||||
#}
|
|
||||||
#userdb {
|
|
||||||
# driver = static
|
|
||||||
# args = uid=vmail gid=mail home=/var/mail/vhosts/%d/%n
|
|
||||||
#}
|
|
||||||
#CONF
|
|
||||||
#chown root:dovecot /etc/dovecot/conf.d/auth-sql.conf.ext
|
|
||||||
#chmod 640 /etc/dovecot/conf.d/auth-sql.conf.ext
|
|
||||||
#
|
|
||||||
## Master-Services (LMTP + AUTH + Listener)
|
|
||||||
#cat > /etc/dovecot/conf.d/10-master.conf <<'CONF'
|
|
||||||
#service lmtp {
|
|
||||||
# unix_listener /var/spool/postfix/private/dovecot-lmtp {
|
|
||||||
# mode = 0600
|
|
||||||
# user = postfix
|
|
||||||
# group = postfix
|
|
||||||
# }
|
|
||||||
#}
|
|
||||||
#service auth {
|
|
||||||
# unix_listener /var/spool/postfix/private/auth {
|
|
||||||
# mode = 0660
|
|
||||||
# user = postfix
|
|
||||||
# group = postfix
|
|
||||||
# }
|
|
||||||
#}
|
|
||||||
#service imap-login {
|
|
||||||
# inet_listener imap {
|
|
||||||
# port = 143
|
|
||||||
# }
|
|
||||||
# inet_listener imaps {
|
|
||||||
# port = 993
|
|
||||||
# ssl = yes
|
|
||||||
# }
|
|
||||||
#}
|
|
||||||
#service pop3-login {
|
|
||||||
# inet_listener pop3 {
|
|
||||||
# port = 110
|
|
||||||
# }
|
|
||||||
# inet_listener pop3s {
|
|
||||||
# port = 995
|
|
||||||
# ssl = yes
|
|
||||||
# }
|
|
||||||
#}
|
|
||||||
#CONF
|
|
||||||
#
|
|
||||||
## SSL – stabile Mail-Pfade
|
|
||||||
#DOVECOT_SSL_CONF="/etc/dovecot/conf.d/10-ssl.conf"
|
|
||||||
#grep -q '^ssl\s*=' "$DOVECOT_SSL_CONF" 2>/dev/null || echo "ssl = required" >> "$DOVECOT_SSL_CONF"
|
|
||||||
#if grep -q '^\s*ssl_cert\s*=' "$DOVECOT_SSL_CONF"; then
|
|
||||||
# sed -i "s|^\s*ssl_cert\s*=.*|ssl_cert = <${MAIL_CERT}|" "$DOVECOT_SSL_CONF"
|
|
||||||
#else
|
|
||||||
# echo "ssl_cert = <${MAIL_CERT}" >> "$DOVECOT_SSL_CONF"
|
|
||||||
#fi
|
|
||||||
#if grep -q '^\s*ssl_key\s*=' "$DOVECOT_SSL_CONF"; then
|
|
||||||
# sed -i "s|^\s*ssl_key\s*=.*|ssl_key = <${MAIL_KEY}|" "$DOVECOT_SSL_CONF"
|
|
||||||
#else
|
|
||||||
# echo "ssl_key = <${MAIL_KEY}" >> "$DOVECOT_SSL_CONF"
|
|
||||||
#fi
|
|
||||||
#
|
|
||||||
## Postfix-Socket-Verzeichnis sicherstellen
|
|
||||||
#mkdir -p /var/spool/postfix/private
|
|
||||||
#chown root:root /var/spool/postfix
|
|
||||||
#chmod 0755 /var/spool/postfix
|
|
||||||
#chown postfix:postfix /var/spool/postfix/private
|
|
||||||
#chmod 0755 /var/spool/postfix/private
|
|
||||||
#
|
|
||||||
## Nur aktivieren – Start/Reload erst nach App/DB in 90-services.sh
|
|
||||||
#systemctl enable dovecot >/dev/null 2>&1 || true
|
#systemctl enable dovecot >/dev/null 2>&1 || true
|
||||||
|
|
@ -21,7 +21,7 @@ RSPAMD_CONTROLLER_PASSWORD="${RSPAMD_CONTROLLER_PASSWORD:-admin}"
|
||||||
# ──────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────
|
||||||
# Rspamd (Controller + Milter)
|
# Rspamd (Controller + Milter)
|
||||||
# ──────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────
|
||||||
install -d -m 0755 /etc/rspamd/local.d
|
install -d -m 0750 /etc/rspamd/local.d
|
||||||
|
|
||||||
if command -v rspamadm >/dev/null 2>&1; then
|
if command -v rspamadm >/dev/null 2>&1; then
|
||||||
RSPAMD_HASH="$(rspamadm pw -p "${RSPAMD_CONTROLLER_PASSWORD}")"
|
RSPAMD_HASH="$(rspamadm pw -p "${RSPAMD_CONTROLLER_PASSWORD}")"
|
||||||
|
|
@ -30,32 +30,94 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat >/etc/rspamd/local.d/worker-controller.inc <<CONF
|
cat >/etc/rspamd/local.d/worker-controller.inc <<CONF
|
||||||
password = "${RSPAMD_HASH}";
|
worker "controller" {
|
||||||
bind_socket = "127.0.0.1:11334";
|
bind_socket = "127.0.0.1:11334";
|
||||||
|
password = "${RSPAMD_HASH}";
|
||||||
|
}
|
||||||
CONF
|
CONF
|
||||||
|
|
||||||
cat >/etc/rspamd/local.d/worker-normal.inc <<'CONF'
|
#cat >/etc/rspamd/local.d/worker-normal.inc <<'CONF'
|
||||||
bind_socket = "127.0.0.1:11332";
|
#worker "normal" {
|
||||||
|
# bind_socket = "127.0.0.1:11333";
|
||||||
|
#}
|
||||||
|
#CONF
|
||||||
|
|
||||||
|
cat >/etc/rspamd/local.d/worker-proxy.inc <<'CONF'
|
||||||
|
worker "proxy" {
|
||||||
|
bind_socket = "127.0.0.1:11333";
|
||||||
|
milter = yes;
|
||||||
|
timeout = 120s;
|
||||||
|
upstream "local" {
|
||||||
|
default = yes;
|
||||||
|
self_scan = yes;
|
||||||
|
}
|
||||||
|
}
|
||||||
CONF
|
CONF
|
||||||
|
|
||||||
|
|
||||||
cat >/etc/rspamd/local.d/milter_headers.conf <<'CONF'
|
cat >/etc/rspamd/local.d/milter_headers.conf <<'CONF'
|
||||||
use = ["authentication-results"];
|
use = ["authentication-results"];
|
||||||
header = "Authentication-Results";
|
header = "Authentication-Results";
|
||||||
CONF
|
CONF
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
# Rspamd Redis-Konfiguration
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
log "Rspamd Redis konfigurieren …"
|
||||||
|
|
||||||
|
: "${REDIS_PASS:=}"
|
||||||
|
|
||||||
|
cat >/etc/rspamd/local.d/redis.conf <<CONF
|
||||||
|
servers = "127.0.0.1:6379";
|
||||||
|
${REDIS_PASS:+password = "${REDIS_PASS}";}
|
||||||
|
db = 0;
|
||||||
|
CONF
|
||||||
|
|
||||||
|
# Eigentümer und Rechte setzen
|
||||||
|
chown root:_rspamd /etc/rspamd/local.d /etc/rspamd/local.d/redis.conf
|
||||||
|
chmod 750 /etc/rspamd/local.d
|
||||||
|
chmod 640 /etc/rspamd/local.d/redis.conf
|
||||||
|
|
||||||
|
# Testweise prüfen, ob Redis erreichbar ist (nicht kritisch)
|
||||||
|
if command -v redis-cli >/dev/null 2>&1; then
|
||||||
|
if [[ -n "${REDIS_PASS}" ]]; then
|
||||||
|
if redis-cli -h 127.0.0.1 -p 6379 -a "${REDIS_PASS}" ping >/dev/null 2>&1; then
|
||||||
|
log "[✓] Redis erreichbar und Passwort akzeptiert."
|
||||||
|
else
|
||||||
|
log "[!] Warnung: Redis antwortet nicht oder Passwort falsch."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if redis-cli -h 127.0.0.1 -p 6379 ping >/dev/null 2>&1; then
|
||||||
|
log "[✓] Redis erreichbar (ohne Passwort)."
|
||||||
|
else
|
||||||
|
log "[!] Warnung: Redis antwortet nicht."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
systemctl enable --now rspamd || true
|
systemctl enable --now rspamd || true
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────
|
||||||
# OpenDKIM – nur wenn DKIM_ENABLE=1
|
# OpenDKIM – nur wenn DKIM_ENABLE=1
|
||||||
# ──────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
if [[ "${DKIM_ENABLE}" != "1" ]]; then
|
if [[ "${DKIM_ENABLE}" != "1" ]]; then
|
||||||
log "DKIM_ENABLE=0 → OpenDKIM wird übersprungen."
|
log "DKIM_ENABLE=0 → OpenDKIM wird übersprungen."
|
||||||
/usr/sbin/postconf -e "smtpd_milters = inet:127.0.0.1:11332"
|
/usr/sbin/postconf -e "milter_default_action = accept"
|
||||||
/usr/sbin/postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"
|
/usr/sbin/postconf -e "milter_protocol = 6"
|
||||||
systemctl reload postfix || true
|
/usr/sbin/postconf -e "smtpd_milters = inet:127.0.0.1:11333"
|
||||||
|
/usr/sbin/postconf -e "non_smtpd_milters = inet:127.0.0.1:11333"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#if [[ "${DKIM_ENABLE}" != "1" ]]; then
|
||||||
|
# log "DKIM_ENABLE=0 → OpenDKIM wird übersprungen."
|
||||||
|
# /usr/sbin/postconf -e "smtpd_milters = inet:127.0.0.1:11332"
|
||||||
|
# /usr/sbin/postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"
|
||||||
|
# systemctl reload postfix || true
|
||||||
|
# exit 0
|
||||||
|
#fi
|
||||||
|
|
||||||
install -d -m 0755 /etc/opendkim
|
install -d -m 0755 /etc/opendkim
|
||||||
install -d -m 0750 /etc/opendkim/keys
|
install -d -m 0750 /etc/opendkim/keys
|
||||||
chown -R opendkim:opendkim /etc/opendkim
|
chown -R opendkim:opendkim /etc/opendkim
|
||||||
|
|
@ -241,10 +303,23 @@ visudo -cf /etc/sudoers.d/mailwolt-dkim >/dev/null
|
||||||
|
|
||||||
# ── Dienst + Postfix-Milter aktivieren ─────────────────────────
|
# ── Dienst + Postfix-Milter aktivieren ─────────────────────────
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable --now opendkim || true
|
systemctl enable opendkim || true
|
||||||
|
|
||||||
/usr/sbin/postconf -e "smtpd_milters = inet:127.0.0.1:11332, inet:127.0.0.1:8891"
|
if command -v /usr/local/sbin/mw-apply-milters >/dev/null 2>&1; then
|
||||||
/usr/sbin/postconf -e "non_smtpd_milters = inet:127.0.0.1:11332, inet:127.0.0.1:8891"
|
/usr/local/sbin/mw-apply-milters
|
||||||
systemctl reload postfix || true
|
else
|
||||||
|
# Fallback: nur Rspamd + OpenDKIM, Port 11333
|
||||||
|
/usr/sbin/postconf -e "milter_default_action = accept"
|
||||||
|
/usr/sbin/postconf -e "milter_protocol = 6"
|
||||||
|
/usr/sbin/postconf -e "smtpd_milters = inet:127.0.0.1:11333, inet:127.0.0.1:8891"
|
||||||
|
/usr/sbin/postconf -e "non_smtpd_milters = inet:127.0.0.1:11333, inet:127.0.0.1:8891"
|
||||||
|
systemctl reload postfix || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
chgrp _rspamd /etc/rspamd/local.d/*.inc /etc/rspamd/local.d/*.conf || true
|
||||||
|
chmod 0640 /etc/rspamd/local.d/*.inc /etc/rspamd/local.d/*.conf || true
|
||||||
|
|
||||||
|
#/usr/sbin/postconf -e "smtpd_milters = inet:127.0.0.1:11332, inet:127.0.0.1:8891"
|
||||||
|
#/usr/sbin/postconf -e "non_smtpd_milters = inet:127.0.0.1:11332, inet:127.0.0.1:8891"
|
||||||
|
|
||||||
log "[✓] Rspamd + OpenDKIM eingerichtet (läuft; signiert, sobald Keys vorhanden sind)."
|
log "[✓] Rspamd + OpenDKIM eingerichtet (läuft; signiert, sobald Keys vorhanden sind)."
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
source ./lib.sh
|
||||||
|
|
||||||
|
log "OpenDMARC installieren/konfigurieren …"
|
||||||
|
|
||||||
|
# Flags laden
|
||||||
|
set +u
|
||||||
|
[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env
|
||||||
|
set -u
|
||||||
|
OPENDMARC_ENABLE="${OPENDMARC_ENABLE:-1}"
|
||||||
|
|
||||||
|
# Paket sicherstellen
|
||||||
|
if ! dpkg -s opendmarc >/dev/null 2>&1; then
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y opendmarc
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Config-Verzeichnisse
|
||||||
|
install -d -m 0755 /etc/opendmarc
|
||||||
|
install -d -m 0755 /run/opendmarc
|
||||||
|
|
||||||
|
# IgnoreHosts
|
||||||
|
cat >/etc/opendmarc/ignore.hosts <<'EOF'
|
||||||
|
127.0.0.1
|
||||||
|
::1
|
||||||
|
localhost
|
||||||
|
EOF
|
||||||
|
chmod 0644 /etc/opendmarc/ignore.hosts
|
||||||
|
|
||||||
|
# Hauptkonfiguration
|
||||||
|
cat >/etc/opendmarc.conf <<'EOF'
|
||||||
|
AuthservID mailwolt
|
||||||
|
TrustedAuthservIDs mailwolt
|
||||||
|
IgnoreHosts /etc/opendmarc/ignore.hosts
|
||||||
|
Syslog true
|
||||||
|
SoftwareHeader true
|
||||||
|
Socket local:/run/opendmarc/opendmarc.sock
|
||||||
|
RejectFailures false
|
||||||
|
EOF
|
||||||
|
chmod 0644 /etc/opendmarc.conf
|
||||||
|
|
||||||
|
# systemd Drop-in für RuntimeDirectory (robust nach Reboot)
|
||||||
|
install -d -m 0755 /etc/systemd/system/opendmarc.service.d
|
||||||
|
cat >/etc/systemd/system/opendmarc.service.d/override.conf <<'EOF'
|
||||||
|
[Service]
|
||||||
|
RuntimeDirectory=opendmarc
|
||||||
|
RuntimeDirectoryMode=0755
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
# Dienst nach Flag
|
||||||
|
if [[ "$OPENDMARC_ENABLE" = "1" ]]; then
|
||||||
|
systemctl enable --now opendmarc
|
||||||
|
else
|
||||||
|
systemctl disable --now opendmarc || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Postfix-Milter-Kette konsistent setzen (Rspamd + OpenDKIM + optional OpenDMARC)
|
||||||
|
if command -v /usr/local/sbin/mw-apply-milters >/dev/null 2>&1; then
|
||||||
|
/usr/local/sbin/mw-apply-milters
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "[✓] OpenDMARC (ENABLE=${OPENDMARC_ENABLE}) bereit."
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
source ./lib.sh
|
||||||
|
|
||||||
|
log "ClamAV (clamav-daemon) installieren/konfigurieren …"
|
||||||
|
|
||||||
|
# Flags laden
|
||||||
|
set +u
|
||||||
|
[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env
|
||||||
|
set -u
|
||||||
|
CLAMAV_ENABLE="${CLAMAV_ENABLE:-0}"
|
||||||
|
|
||||||
|
# Pakete
|
||||||
|
if ! dpkg -s clamav-daemon >/dev/null 2>&1; then
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y clamav clamav-daemon
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Signaturen aktualisieren (erst Freshclam starten)
|
||||||
|
systemctl stop clamav-freshclam 2>/dev/null || true
|
||||||
|
freshclam || true
|
||||||
|
systemctl start clamav-freshclam || true
|
||||||
|
|
||||||
|
# clamd LocalSocket setzen
|
||||||
|
sed -i 's|^#\?LocalSocket .*|LocalSocket /run/clamav/clamd.ctl|' /etc/clamav/clamd.conf || true
|
||||||
|
install -d -m 0755 /run/clamav
|
||||||
|
chown clamav:clamav /run/clamav
|
||||||
|
|
||||||
|
# Dienst nach Flag
|
||||||
|
if [[ "$CLAMAV_ENABLE" = "1" ]]; then
|
||||||
|
systemctl enable --now clamav-daemon
|
||||||
|
else
|
||||||
|
systemctl disable --now clamav-daemon || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Rspamd-Integration (nur wenn aktiv)
|
||||||
|
AV_CONF="/etc/rspamd/local.d/antivirus.conf"
|
||||||
|
if [[ "$CLAMAV_ENABLE" = "1" ]]; then
|
||||||
|
cat >"$AV_CONF" <<'EOF'
|
||||||
|
clamav {
|
||||||
|
symbol = "CLAM_VIRUS";
|
||||||
|
type = "clamav";
|
||||||
|
servers = "/run/clamav/clamd.ctl";
|
||||||
|
scan_mime_parts = true;
|
||||||
|
scan_text_mime = true;
|
||||||
|
max_size = 50mb;
|
||||||
|
log_clean = false;
|
||||||
|
action = "reject";
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
chown root:_rspamd "$AV_CONF" || true
|
||||||
|
chmod 0640 "$AV_CONF" || true
|
||||||
|
systemctl reload rspamd || systemctl restart rspamd
|
||||||
|
else
|
||||||
|
rm -f "$AV_CONF" || true
|
||||||
|
systemctl reload rspamd || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "[✓] ClamAV (ENABLE=${CLAMAV_ENABLE}) konfiguriert."
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
source ./lib.sh
|
||||||
|
|
||||||
|
log "Fail2Ban installieren/konfigurieren …"
|
||||||
|
|
||||||
|
# Flags laden
|
||||||
|
set +u
|
||||||
|
[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env
|
||||||
|
set -u
|
||||||
|
FAIL2BAN_ENABLE="${FAIL2BAN_ENABLE:-1}"
|
||||||
|
|
||||||
|
# Paket
|
||||||
|
if ! dpkg -s fail2ban >/dev/null 2>&1; then
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y fail2ban
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -d -m 0755 /etc/fail2ban/jail.d
|
||||||
|
|
||||||
|
# Basis-Jails (praxisnah)
|
||||||
|
cat >/etc/fail2ban/jail.d/mailwolt.conf <<'EOF'
|
||||||
|
[DEFAULT]
|
||||||
|
bantime = 1h
|
||||||
|
findtime = 10m
|
||||||
|
maxretry = 5
|
||||||
|
backend = auto
|
||||||
|
|
||||||
|
[sshd]
|
||||||
|
enabled = true
|
||||||
|
port = ssh
|
||||||
|
logpath = /var/log/auth.log
|
||||||
|
|
||||||
|
[postfix]
|
||||||
|
enabled = true
|
||||||
|
logpath = /var/log/mail.log
|
||||||
|
port = smtp,ssmtp,submission,465
|
||||||
|
|
||||||
|
[dovecot]
|
||||||
|
enabled = true
|
||||||
|
logpath = /var/log/mail.log
|
||||||
|
port = pop3,pop3s,imap,imaps,submission,465,587,993
|
||||||
|
|
||||||
|
# Optional: Rspamd-Controller-Auth (nur wenn Passwort/Basic-Auth genutzt wird)
|
||||||
|
[rspamd-controller]
|
||||||
|
enabled = true
|
||||||
|
port = 11334
|
||||||
|
filter = rspamd
|
||||||
|
logpath = /var/log/rspamd/rspamd.log
|
||||||
|
maxretry = 5
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# einfacher Filter für Rspamd-Controller
|
||||||
|
if [ ! -f /etc/fail2ban/filter.d/rspamd.conf ]; then
|
||||||
|
cat >/etc/fail2ban/filter.d/rspamd.conf <<'EOF'
|
||||||
|
[Definition]
|
||||||
|
failregex = .*Authentication failed for user.* from <HOST>
|
||||||
|
ignoreregex =
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dienst nach Flag
|
||||||
|
if [[ "$FAIL2BAN_ENABLE" = "1" ]]; then
|
||||||
|
systemctl enable --now fail2ban
|
||||||
|
else
|
||||||
|
systemctl disable --now fail2ban || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "[✓] Fail2Ban (ENABLE=${FAIL2BAN_ENABLE}) bereit."
|
||||||
|
|
@ -63,11 +63,6 @@ if [[ "${BASE_DOMAIN}" != "example.com" ]]; then
|
||||||
issue "${WEBMAIL_HOST:-}"
|
issue "${WEBMAIL_HOST:-}"
|
||||||
issue "${MAIL_HOSTNAME:-}"
|
issue "${MAIL_HOSTNAME:-}"
|
||||||
|
|
||||||
# Falls der Deploy-Wrapper gerade erst installiert wurde:
|
|
||||||
# if [[ -x /usr/local/sbin/mw-deploy.sh ]]; then
|
|
||||||
# /usr/local/sbin/mw-deploy.sh || true
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# Nginx nur neu laden, wenn aktiv
|
# Nginx nur neu laden, wenn aktiv
|
||||||
if systemctl is-active --quiet nginx; then
|
if systemctl is-active --quiet nginx; then
|
||||||
systemctl reload nginx || true
|
systemctl reload nginx || true
|
||||||
|
|
@ -75,238 +70,3 @@ if [[ "${BASE_DOMAIN}" != "example.com" ]]; then
|
||||||
else
|
else
|
||||||
echo "[i] BASE_DOMAIN=example.com – LE wird übersprungen."
|
echo "[i] BASE_DOMAIN=example.com – LE wird übersprungen."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
##!/usr/bin/env bash
|
|
||||||
#set -euo pipefail
|
|
||||||
#source ./lib.sh
|
|
||||||
#
|
|
||||||
#ACME_WEBROOT="/var/www/letsencrypt"
|
|
||||||
#install -d -m 0755 "${ACME_WEBROOT}/.well-known/acme-challenge"
|
|
||||||
#
|
|
||||||
#CERTBOT_EXTRA=()
|
|
||||||
#LE_STAGING="${LE_STAGING:-0}" # 1 = Let's Encrypt Staging aktivieren
|
|
||||||
#[[ "$LE_STAGING" = "1" ]] && CERTBOT_EXTRA+=(--test-cert)
|
|
||||||
#
|
|
||||||
#resolve_ok() {
|
|
||||||
# local host="$1"
|
|
||||||
# local pats=()
|
|
||||||
# [[ -n "${SERVER_PUBLIC_IPV4:-}" ]] && pats+=("${SERVER_PUBLIC_IPV4//./\\.}")
|
|
||||||
# [[ -n "${SERVER_PUBLIC_IPV6:-}" ]] && pats+=("${SERVER_PUBLIC_IPV6//:/\\:}")
|
|
||||||
# # Wenn gar nichts bekannt ist, lieber nicht blockieren:
|
|
||||||
# [[ ${#pats[@]} -eq 0 ]] && return 0
|
|
||||||
# getent ahosts "$host" | awk '{print $1}' | sort -u \
|
|
||||||
# | grep -Eq "^($(IFS='|'; echo "${pats[*]}"))$"
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
#probe_http() {
|
|
||||||
# local host="$1"
|
|
||||||
# echo test > "${ACME_WEBROOT}/.well-known/acme-challenge/_probe"
|
|
||||||
# curl -fsS --max-time 5 -4 "http://${host}/.well-known/acme-challenge/_probe" >/dev/null \
|
|
||||||
# || curl -fsS --max-time 5 -6 "http://${host}/.well-known/acme-challenge/_probe" >/dev/null
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
#issue() {
|
|
||||||
# local host="$1"
|
|
||||||
# echo "[i] Versuche LE für ${host} …"
|
|
||||||
# resolve_ok "$host" || { echo "[!] DNS zeigt (noch) nicht hierher – skip ${host}"; return 0; }
|
|
||||||
#
|
|
||||||
# if ! probe_http "$host"; then
|
|
||||||
# echo "[!] ACME-HTTP-Check für ${host} fehlgeschlagen (Port 80/IPv6/Firewall/Nginx prüfen)."
|
|
||||||
# fi
|
|
||||||
#
|
|
||||||
# # MX: Key beibehalten (TLSA 3 1 1 bleibt stabil)
|
|
||||||
# EXTRA_ARGS=()
|
|
||||||
# [[ "$host" == "$MAIL_HOSTNAME" ]] && EXTRA_ARGS+=(--reuse-key)
|
|
||||||
#
|
|
||||||
# certbot certonly --agree-tos -m "${LE_EMAIL:-admin@${BASE_DOMAIN}}" \
|
|
||||||
# --non-interactive --webroot -w "$ACME_WEBROOT" -d "$host" \
|
|
||||||
# "${EXTRA_ARGS[@]}" "${CERTBOT_EXTRA[@]}" || true
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
#if [[ "$BASE_DOMAIN" != "example.com" ]]; then
|
|
||||||
# issue "$UI_HOST"
|
|
||||||
# issue "$WEBMAIL_HOST"
|
|
||||||
# issue "$MAIL_HOSTNAME"
|
|
||||||
#
|
|
||||||
#run-parts /etc/letsencrypt/renewal-hooks/deploy || true
|
|
||||||
#systemctl reload nginx || true
|
|
||||||
#
|
|
||||||
## # TLSA direkt einmal schreiben (Hook macht es bei Renewals sowieso)
|
|
||||||
## MX_CERT="/etc/letsencrypt/live/${MAIL_HOSTNAME}/fullchain.pem"
|
|
||||||
## if [[ -s "$MX_CERT" ]]; then
|
|
||||||
## HASH="$(openssl x509 -in "$MX_CERT" -noout -pubkey \
|
|
||||||
## | openssl pkey -pubin -outform DER \
|
|
||||||
## | openssl dgst -sha256 | sed 's/^.*= //')"
|
|
||||||
## TLSA_LINE="_25._tcp.${MAIL_HOSTNAME}. IN TLSA 3 1 1 ${HASH}"
|
|
||||||
## install -d -m 0755 /etc/mailwolt/dns
|
|
||||||
## echo "${TLSA_LINE}" > "/etc/mailwolt/dns/${MAIL_HOSTNAME}.tlsa.txt"
|
|
||||||
## echo "[TLSA] ${TLSA_LINE}"
|
|
||||||
## fi
|
|
||||||
#else
|
|
||||||
# echo "[i] BASE_DOMAIN=example.com – LE wird übersprungen."
|
|
||||||
#fi
|
|
||||||
|
|
||||||
|
|
||||||
##!/usr/bin/env bash
|
|
||||||
#set -euo pipefail
|
|
||||||
#source ./lib.sh
|
|
||||||
#
|
|
||||||
#ACME_WEBROOT="/var/www/letsencrypt"
|
|
||||||
#install -d -m 0755 "${ACME_WEBROOT}/.well-known/acme-challenge"
|
|
||||||
#
|
|
||||||
## Let's Encrypt: Staging optional (für Tests)
|
|
||||||
#CERTBOT_EXTRA=()
|
|
||||||
#LE_STAGING="${LE_STAGING:-0}"
|
|
||||||
#[[ "$LE_STAGING" = "1" ]] && CERTBOT_EXTRA+=(--test-cert)
|
|
||||||
#
|
|
||||||
## Einheitliche LE-E-Mail mit Fallback
|
|
||||||
#LE_MAIL="${LE_EMAIL:-admin@${BASE_DOMAIN}}"
|
|
||||||
#
|
|
||||||
## DNS zeigt auf diese Kiste?
|
|
||||||
#resolve_ok() {
|
|
||||||
# local host="$1"
|
|
||||||
# local pats=()
|
|
||||||
# [[ -n "${SERVER_PUBLIC_IPV4:-}" ]] && pats+=("${SERVER_PUBLIC_IPV4//./\\.}")
|
|
||||||
# [[ -n "${SERVER_PUBLIC_IPV6:-}" ]] && pats+=("${SERVER_PUBLIC_IPV6//:/\\:}")
|
|
||||||
# [[ ${#pats[@]} -eq 0 ]] && return 0
|
|
||||||
# getent ahosts "$host" | awk '{print $1}' | sort -u \
|
|
||||||
# | grep -Eq "^($(IFS='|'; echo "${pats[*]}"))$"
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
## HTTP-01 erreichbar?
|
|
||||||
#probe_http() {
|
|
||||||
# local host="$1"
|
|
||||||
# echo test > "${ACME_WEBROOT}/.well-known/acme-challenge/_probe"
|
|
||||||
# curl -fsS --max-time 5 -4 "http://${host}/.well-known/acme-challenge/_probe" >/dev/null \
|
|
||||||
# || curl -fsS --max-time 5 -6 "http://${host}/.well-known/acme-challenge/_probe" >/dev/null
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
## Ein Zertifikat ausstellen
|
|
||||||
#issue() {
|
|
||||||
# local host="$1"
|
|
||||||
# [[ -z "$host" ]] && return 0
|
|
||||||
#
|
|
||||||
# echo "[i] Versuche LE für ${host} …"
|
|
||||||
#
|
|
||||||
# if ! resolve_ok "$host"; then
|
|
||||||
# echo "[!] DNS zeigt (noch) nicht hierher – überspringe: ${host}"
|
|
||||||
# return 0
|
|
||||||
# fi
|
|
||||||
#
|
|
||||||
# if ! probe_http "$host"; then
|
|
||||||
# echo "[!] ACME-HTTP-Check für ${host} fehlgeschlagen (Port 80/IPv6/Firewall/Nginx prüfen)."
|
|
||||||
# fi
|
|
||||||
#
|
|
||||||
# EXTRA_ARGS=()
|
|
||||||
# # MX: Key wiederverwenden → stabiler TLSA-Hash (3 1 1)
|
|
||||||
# [[ "${host}" == "${MAIL_HOSTNAME}" ]] && EXTRA_ARGS+=(--reuse-key)
|
|
||||||
#
|
|
||||||
#certbot certonly \
|
|
||||||
# --agree-tos -m "${LE_MAIL}" --non-interactive \
|
|
||||||
# --webroot -w "${ACME_WEBROOT}" -d "${host}" \
|
|
||||||
# "${EXTRA_ARGS[@]}" "${CERTBOT_EXTRA[@]}" || true
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
## ------------------- Hauptlauf -------------------
|
|
||||||
#if [[ "${BASE_DOMAIN}" != "example.com" ]]; then
|
|
||||||
# issue "${UI_HOST:-}"
|
|
||||||
# issue "${WEBMAIL_HOST:-}"
|
|
||||||
# issue "${MAIL_HOSTNAME:-}"
|
|
||||||
#
|
|
||||||
# # Falls Deploy-Hook erst JETZT angelegt wurde: einmal manuell ausführen
|
|
||||||
# if [[ -x /usr/local/sbin/mw-deploy.sh ]]; then
|
|
||||||
# /usr/local/sbin/mw-deploy.sh || true
|
|
||||||
# fi
|
|
||||||
#
|
|
||||||
# # Nginx nur neu laden, wenn aktiv
|
|
||||||
# if systemctl is-active --quiet nginx; then
|
|
||||||
# systemctl reload nginx || true
|
|
||||||
# fi
|
|
||||||
#else
|
|
||||||
# echo "[i] BASE_DOMAIN=example.com – LE wird übersprungen."
|
|
||||||
#fi
|
|
||||||
|
|
||||||
##!/usr/bin/env bash
|
|
||||||
#set -euo pipefail
|
|
||||||
#source ./lib.sh
|
|
||||||
#
|
|
||||||
#ACME_WEBROOT="/var/www/letsencrypt"
|
|
||||||
#install -d -m 0755 "${ACME_WEBROOT}/.well-known/acme-challenge"
|
|
||||||
#
|
|
||||||
## Let's Encrypt: Staging optional aktivieren (keine echten Zertifikate)
|
|
||||||
#CERTBOT_EXTRA=()
|
|
||||||
#LE_STAGING="${LE_STAGING:-0}" # 1 = Staging
|
|
||||||
#[[ "$LE_STAGING" = "1" ]] && CERTBOT_EXTRA+=(--test-cert)
|
|
||||||
#
|
|
||||||
## Einheitliche LE-E-Mail mit Fallback
|
|
||||||
#LE_MAIL="${LE_EMAIL:-admin@${BASE_DOMAIN}}"
|
|
||||||
#
|
|
||||||
## DNS-Auflösung gegen unsere bekannte(n) IP(s) prüfen (nur als Warnsignal)
|
|
||||||
#resolve_ok() {
|
|
||||||
# local host="$1"
|
|
||||||
# local pats=()
|
|
||||||
# [[ -n "${SERVER_PUBLIC_IPV4:-}" ]] && pats+=("${SERVER_PUBLIC_IPV4//./\\.}")
|
|
||||||
# [[ -n "${SERVER_PUBLIC_IPV6:-}" ]] && pats+=("${SERVER_PUBLIC_IPV6//:/\\:}")
|
|
||||||
# [[ ${#pats[@]} -eq 0 ]] && return 0
|
|
||||||
# getent ahosts "$host" | awk '{print $1}' | sort -u \
|
|
||||||
# | grep -Eq "^($(IFS='|'; echo "${pats[*]}"))$"
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
## HTTP-01 Erreichbarkeit schnell antesten (IPv4/IPv6)
|
|
||||||
#probe_http() {
|
|
||||||
# local host="$1"
|
|
||||||
# echo test > "${ACME_WEBROOT}/.well-known/acme-challenge/_probe"
|
|
||||||
# curl -fsS --max-time 5 -4 "http://${host}/.well-known/acme-challenge/_probe" >/dev/null \
|
|
||||||
# || curl -fsS --max-time 5 -6 "http://${host}/.well-known/acme-challenge/_probe" >/dev/null
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
## Ein Zertifikat für einen Host ausstellen
|
|
||||||
#issue() {
|
|
||||||
# local host="$1"
|
|
||||||
# [[ -z "$host" ]] && return 0
|
|
||||||
#
|
|
||||||
# echo "[i] Versuche LE für ${host} …"
|
|
||||||
#
|
|
||||||
# if ! resolve_ok "$host"; then
|
|
||||||
# echo "[!] DNS zeigt (noch) nicht hierher – überspringe: ${host}"
|
|
||||||
# return 0
|
|
||||||
# fi
|
|
||||||
#
|
|
||||||
# if ! probe_http "$host"; then
|
|
||||||
# echo "[!] ACME-HTTP-Check für ${host} fehlgeschlagen (Port 80/IPv6/Firewall/Nginx prüfen)."
|
|
||||||
# # wir versuchen es trotzdem – Certbot meldet sich, falls es scheitert
|
|
||||||
# fi
|
|
||||||
#
|
|
||||||
# # Für MX den Key wiederverwenden (stabiler TLSA-Hash 3 1 1)
|
|
||||||
# EXTRA_ARGS=()
|
|
||||||
# [[ "${host}" == "${MAIL_HOSTNAME}" ]] && EXTRA_ARGS+=(--reuse-key)
|
|
||||||
#
|
|
||||||
# certbot certonly \
|
|
||||||
# --agree-tos -m "${LE_MAIL}" --non-interactive \
|
|
||||||
# --webroot -w "${ACME_WEBROOT}" -d "${host}" \
|
|
||||||
# --deploy-hook /usr/local/sbin/mw-deploy.sh \
|
|
||||||
# "${EXTRA_ARGS[@]}" "${CERTBOT_EXTRA[@]}" || true
|
|
||||||
#}
|
|
||||||
#
|
|
||||||
## -----------------------------------------------------------------------------
|
|
||||||
## Hauptlauf
|
|
||||||
## -----------------------------------------------------------------------------
|
|
||||||
#if [[ "${BASE_DOMAIN}" != "example.com" ]]; then
|
|
||||||
# issue "${UI_HOST:-}"
|
|
||||||
# issue "${WEBMAIL_HOST:-}"
|
|
||||||
# issue "${MAIL_HOSTNAME:-}"
|
|
||||||
#
|
|
||||||
# # Der Deploy-Hook hat Symlinks bereits gesetzt und nginx ggf. neu geladen.
|
|
||||||
# # Optional trotzdem manuell ausführen (harmlos, hilft bei exotischen Setups):
|
|
||||||
# if [[ -d /etc/letsencrypt/renewal-hooks/deploy ]]; then
|
|
||||||
# run-parts /etc/letsencrypt/renewal-hooks/deploy || true
|
|
||||||
# fi
|
|
||||||
# if systemctl is-active --quiet nginx; then
|
|
||||||
# systemctl reload nginx || true
|
|
||||||
# fi
|
|
||||||
#else
|
|
||||||
# echo "[i] BASE_DOMAIN=example.com – LE-Ausstellung wird übersprungen."
|
|
||||||
#fi
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ if [[ "${DKIM_ENABLE}" = "1" && -n "${SYSMAIL_DOMAIN}" ]]; then
|
||||||
rm -f "$TMP_TXT" || true
|
rm -f "$TMP_TXT" || true
|
||||||
|
|
||||||
# 3) OpenDKIM neu laden
|
# 3) OpenDKIM neu laden
|
||||||
systemctl reload opendkim || systemctl restart opendkim || true
|
touch /run/mailwolt.need-opendkim-reload || true
|
||||||
else
|
else
|
||||||
log "DKIM übersprungen (DKIM_ENABLE=${DKIM_ENABLE}, SYSMAIL_DOMAIN='${SYSMAIL_DOMAIN}')."
|
log "DKIM übersprungen (DKIM_ENABLE=${DKIM_ENABLE}, SYSMAIL_DOMAIN='${SYSMAIL_DOMAIN}')."
|
||||||
fi
|
fi
|
||||||
|
|
@ -262,5 +262,5 @@ chown -R "$APP_USER":"$APP_GROUP" "$APP_DIR"
|
||||||
chmod -R u=rwX,g=rwX,o=rX "$APP_DIR"
|
chmod -R u=rwX,g=rwX,o=rX "$APP_DIR"
|
||||||
install -d -m 0775 -o "$APP_USER" -g "$APP_GROUP" "$APP_DIR/storage" "$APP_DIR/bootstrap/cache"
|
install -d -m 0775 -o "$APP_USER" -g "$APP_GROUP" "$APP_DIR/storage" "$APP_DIR/bootstrap/cache"
|
||||||
|
|
||||||
relink_and_reload
|
#relink_and_reload
|
||||||
systemctl restart php*-fpm || true
|
#systemctl restart php*-fpm || true
|
||||||
|
|
|
||||||
|
|
@ -94,14 +94,28 @@ fi
|
||||||
systemctl enable --now ${APP_USER}-schedule
|
systemctl enable --now ${APP_USER}-schedule
|
||||||
systemctl enable --now ${APP_USER}-queue
|
systemctl enable --now ${APP_USER}-queue
|
||||||
|
|
||||||
# Webstack
|
# Mail-Dienste starten
|
||||||
systemctl reload nginx || true
|
systemctl enable --now rspamd opendkim postfix dovecot || true
|
||||||
systemctl restart php*-fpm || true
|
|
||||||
|
|
||||||
# Mail-Dienste JETZT starten (damit 25/465/587 offen sind)
|
# PHP-FPM: Unit erkennen, enable + (re)load
|
||||||
systemctl enable --now rspamd opendkim || true
|
enable_and_touch_php_fpm() {
|
||||||
systemctl enable --now postfix
|
for u in php8.3-fpm php8.2-fpm php8.1-fpm php8.0-fpm php7.4-fpm php-fpm; do
|
||||||
systemctl enable --now dovecot
|
if systemctl list-unit-files | grep -q "^${u}\.service"; then
|
||||||
|
systemctl enable --now "$u" || true
|
||||||
|
systemctl reload "$u" || systemctl restart "$u" || true
|
||||||
|
echo "[i] PHP-FPM unit: $u"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "[!] Keine passende php-fpm Unit gefunden."
|
||||||
|
}
|
||||||
|
enable_and_touch_php_fpm
|
||||||
|
|
||||||
|
# Falls in 80-app.sh DKIM installiert wurde: jetzt einmal reloaden
|
||||||
|
if [[ -e /run/mailwolt.need-opendkim-reload ]]; then
|
||||||
|
systemctl reload opendkim || true
|
||||||
|
rm -f /run/mailwolt.need-opendkim-reload || true
|
||||||
|
fi
|
||||||
|
|
||||||
# Falls DB-Migration schon durch: einmal reload
|
# Falls DB-Migration schon durch: einmal reload
|
||||||
db_ready(){ mysql -u"${DB_USER}" -p"${DB_PASS}" -h 127.0.0.1 -D "${DB_NAME}" -e "SHOW TABLES LIKE 'migrations'\G" >/dev/null 2>&1; }
|
db_ready(){ mysql -u"${DB_USER}" -p"${DB_PASS}" -h 127.0.0.1 -D "${DB_NAME}" -e "SHOW TABLES LIKE 'migrations'\G" >/dev/null 2>&1; }
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,8 @@ chmod 600 /etc/monit/monitrc
|
||||||
monit -t && systemctl enable --now monit
|
monit -t && systemctl enable --now monit
|
||||||
monit reload || true
|
monit reload || true
|
||||||
|
|
||||||
log "[✓] Monit konfiguriert und gestartet"
|
log "[✓] Monit konfiguriert und gestartet"
|
||||||
|
|
||||||
|
# ── mailwolt-update ins System kopieren ─────────────────────────────
|
||||||
|
install -m 0750 -o root -g root scripts/update.sh /usr/local/sbin/mailwolt-update
|
||||||
|
log "[✓] mailwolt-update installiert → ausführbar via 'sudo mailwolt-update'"
|
||||||
|
|
@ -0,0 +1,175 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
source ./lib.sh
|
||||||
|
|
||||||
|
log "WoltGuard (Monit + Self-Heal) einrichten …"
|
||||||
|
|
||||||
|
set +u
|
||||||
|
[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env
|
||||||
|
set -u
|
||||||
|
CLAMAV_ENABLE="${CLAMAV_ENABLE:-0}"
|
||||||
|
OPENDMARC_ENABLE="${OPENDMARC_ENABLE:-0}"
|
||||||
|
FAIL2BAN_ENABLE="${FAIL2BAN_ENABLE:-1}"
|
||||||
|
|
||||||
|
# Pakete sicherstellen
|
||||||
|
command -v monit >/dev/null || { apt-get update -qq; apt-get install -y monit; }
|
||||||
|
systemctl enable --now monit
|
||||||
|
|
||||||
|
# Helper-Skripte
|
||||||
|
install -d -m 0755 /usr/local/sbin
|
||||||
|
cat >/usr/local/sbin/mw-redis-ping.sh <<'EOSH'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
PASS=""
|
||||||
|
[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env || true
|
||||||
|
if command -v redis-cli >/dev/null 2>&1; then
|
||||||
|
[[ -n "${REDIS_PASS:-}" ]] \
|
||||||
|
&& redis-cli -h 127.0.0.1 -p 6379 -a "$REDIS_PASS" ping | grep -q PONG \
|
||||||
|
|| redis-cli -h 127.0.0.1 -p 6379 ping | grep -q PONG
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EOSH
|
||||||
|
chmod 0755 /usr/local/sbin/mw-redis-ping.sh
|
||||||
|
|
||||||
|
cat >/usr/local/sbin/mw-rspamd-heal.sh <<'EOSH'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
install -d -m 0755 -o _rspamd -g _rspamd /run/rspamd || true
|
||||||
|
[ -S /var/lib/rspamd/rspamd.sock ] && rm -f /var/lib/rspamd/rspamd.sock || true
|
||||||
|
systemctl restart rspamd
|
||||||
|
EOSH
|
||||||
|
chmod 0755 /usr/local/sbin/mw-rspamd-heal.sh
|
||||||
|
|
||||||
|
# WoltGuard Wrapper + Unit
|
||||||
|
cat >/usr/local/bin/woltguard <<'EOSH'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
case "${1:-status}" in
|
||||||
|
start) systemctl enable --now monit ;;
|
||||||
|
stop) systemctl stop monit ;;
|
||||||
|
status) monit summary || systemctl status monit || true ;;
|
||||||
|
heal) monit reload || true; sleep 1; monit restart all || true ;;
|
||||||
|
monitor) monit monitor all || true ;;
|
||||||
|
unmonitor) monit unmonitor all || true ;;
|
||||||
|
*) echo "Usage: woltguard {start|stop|status|heal|monitor|unmonitor}"; exit 2;;
|
||||||
|
esac
|
||||||
|
EOSH
|
||||||
|
chmod 0755 /usr/local/bin/woltguard
|
||||||
|
|
||||||
|
cat >/etc/systemd/system/woltguard.service <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=WoltGuard – Self-Healing Monitor for MailWolt
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/woltguard start
|
||||||
|
ExecStop=/usr/local/bin/woltguard stop
|
||||||
|
RemainAfterExit=yes
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now woltguard
|
||||||
|
|
||||||
|
# Monit Basis + include
|
||||||
|
sed -i 's/^set daemon .*/set daemon 30/' /etc/monit/monitrc || true
|
||||||
|
grep -q 'include /etc/monit/conf.d/*' /etc/monit/monitrc || echo 'include /etc/monit/conf.d/*' >>/etc/monit/monitrc
|
||||||
|
install -d -m 0755 /etc/monit/conf.d
|
||||||
|
|
||||||
|
# Checks
|
||||||
|
cat >/etc/monit/conf.d/postfix.conf <<'EOF'
|
||||||
|
check process postfix with pidfile /var/spool/postfix/pid/master.pid
|
||||||
|
start program = "/bin/systemctl start postfix"
|
||||||
|
stop program = "/bin/systemctl stop postfix"
|
||||||
|
if failed port 25 protocol smtp then restart
|
||||||
|
if failed port 465 type tcpssl then restart
|
||||||
|
if failed port 587 type tcp then restart
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >/etc/monit/conf.d/dovecot.conf <<'EOF'
|
||||||
|
check process dovecot with pidfile /run/dovecot/master.pid
|
||||||
|
start program = "/bin/systemctl start dovecot"
|
||||||
|
stop program = "/bin/systemctl stop dovecot"
|
||||||
|
if failed port 993 type tcpssl for 2 cycles then restart
|
||||||
|
if failed port 24 protocol lmtp for 2 cycles then restart
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >/etc/monit/conf.d/nginx.conf <<'EOF'
|
||||||
|
check process nginx with pidfile /run/nginx.pid
|
||||||
|
start program = "/bin/systemctl start nginx"
|
||||||
|
stop program = "/bin/systemctl stop nginx"
|
||||||
|
if failed port 80 type tcp then restart
|
||||||
|
if failed port 443 type tcpssl then restart
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >/etc/monit/conf.d/redis.conf <<'EOF'
|
||||||
|
check process redis with pidfile /run/redis/redis-server.pid
|
||||||
|
start program = "/bin/systemctl start redis-server"
|
||||||
|
stop program = "/bin/systemctl stop redis-server"
|
||||||
|
if failed host 127.0.0.1 port 6379 for 2 cycles then restart
|
||||||
|
if failed program "/usr/local/sbin/mw-redis-ping.sh" for 2 cycles then restart
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >/etc/monit/conf.d/rspamd.conf <<'EOF'
|
||||||
|
check process rspamd with pidfile /run/rspamd/rspamd.pid
|
||||||
|
start program = "/bin/systemctl start rspamd"
|
||||||
|
stop program = "/bin/systemctl stop rspamd"
|
||||||
|
if failed port 11333 for 2 cycles then exec "/usr/local/sbin/mw-rspamd-heal.sh"
|
||||||
|
if failed port 11334 for 2 cycles then exec "/usr/local/sbin/mw-rspamd-heal.sh"
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >/etc/monit/conf.d/opendkim.conf <<'EOF'
|
||||||
|
check process opendkim with pidfile /run/opendkim/opendkim.pid
|
||||||
|
start program = "/bin/systemctl start opendkim"
|
||||||
|
stop program = "/bin/systemctl stop opendkim"
|
||||||
|
if does not exist file "/run/opendkim/opendkim.pid" then restart
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# optional: OpenDMARC
|
||||||
|
if [[ "$OPENDMARC_ENABLE" = "1" ]]; then
|
||||||
|
cat >/etc/monit/conf.d/opendmarc.conf <<'EOF'
|
||||||
|
check process opendmarc with pidfile /run/opendmarc/opendmarc.pid
|
||||||
|
start program = "/bin/systemctl start opendmarc"
|
||||||
|
stop program = "/bin/systemctl stop opendmarc"
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
rm -f /etc/monit/conf.d/opendmarc.conf || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# optional: ClamAV
|
||||||
|
if [[ "$CLAMAV_ENABLE" = "1" ]]; then
|
||||||
|
cat >/etc/monit/conf.d/clamav.conf <<'EOF'
|
||||||
|
check process clamd with pidfile /run/clamav/clamd.pid
|
||||||
|
start program = "/bin/systemctl start clamav-daemon"
|
||||||
|
stop program = "/bin/systemctl stop clamav-daemon"
|
||||||
|
if failed unixsocket /run/clamav/clamd.ctl then restart
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
rm -f /etc/monit/conf.d/clamav.conf || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# optional: Fail2Ban
|
||||||
|
if [[ "$FAIL2BAN_ENABLE" = "1" ]]; then
|
||||||
|
cat >/etc/monit/conf.d/fail2ban.conf <<'EOF'
|
||||||
|
check process fail2ban with pidfile /run/fail2ban/fail2ban.pid
|
||||||
|
start program = "/bin/systemctl start fail2ban"
|
||||||
|
stop program = "/bin/systemctl stop fail2ban"
|
||||||
|
if 5 restarts within 5 cycles then alert
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
rm -f /etc/monit/conf.d/fail2ban.conf || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
monit -t
|
||||||
|
systemctl reload monit || systemctl restart monit
|
||||||
|
woltguard status || true
|
||||||
|
log "[✓] WoltGuard aktiv."
|
||||||
|
|
@ -4,130 +4,134 @@ source ./lib.sh
|
||||||
|
|
||||||
log "MOTD installieren …"
|
log "MOTD installieren …"
|
||||||
install -d /usr/local/bin
|
install -d /usr/local/bin
|
||||||
|
|
||||||
cat >/usr/local/bin/mw-motd <<'SH'
|
cat >/usr/local/bin/mw-motd <<'SH'
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# bewusst KEIN "set -e"; MOTD soll nie hart abbrechen
|
# MOTD – MailWolt
|
||||||
|
# bewusst KEIN "set -e" und KEIN pipefail; MOTD darf nie hart abbrechen
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
# Farben
|
# ---------- Farben ----------
|
||||||
NC="\033[0m"; CY="\033[1;36m"; GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m"; GY="\033[0;90m"; WH="\033[1;37m"
|
NC="\033[0m"; WH="\033[1;37m"; CY="\033[1;36m"; GY="\033[0;90m"
|
||||||
|
GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m"
|
||||||
|
|
||||||
# Installer-Variablen (optional)
|
# ---------- Breite / Zentrierung ----------
|
||||||
UI_HOST=""; WEBMAIL_HOST=""; MAIL_HOSTNAME=""; LE_EMAIL=""; PROXY_MODE=""; NPM_IP=""
|
W=110
|
||||||
|
term_cols=$(tput cols 2>/dev/null || echo $W)
|
||||||
|
[ "$term_cols" -gt "$W" ] && pad=$(( (term_cols - W)/2 )) || pad=0
|
||||||
|
sp(){ [ "$1" -gt 0 ] && printf "%${1}s" " " || true; }
|
||||||
|
center() { local s="$1"; local n=$(( (W - ${#s})/2 )); sp $((pad+n)); printf "%s\n" "$s"; }
|
||||||
|
rule(){ sp "$pad"; printf "%0.s=" $(seq 1 "$W"); printf "\n"; }
|
||||||
|
title(){ sp "$pad"; local t="$1"; local lf=$(( (W - ${#t} - 2)/2 )); local rf=$(( W - ${#t} - 2 - lf )); \
|
||||||
|
printf "%s" "$(printf '─%.0s' $(seq 1 $lf))"; printf " %s " "$t"; printf "%s\n" "$(printf '─%.0s' $(seq 1 $rf))"; }
|
||||||
|
kv(){ sp "$pad"; printf "%-12s: %s\n" "$1" "$2"; }
|
||||||
|
|
||||||
|
# ---------- Installer-/App-Variablen ----------
|
||||||
|
UI_HOST=""; WEBMAIL_HOST=""; MAIL_HOSTNAME=""
|
||||||
[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env || true
|
[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env || true
|
||||||
# Aus .env (falls vorhanden)
|
|
||||||
if [ -r /var/www/mailwolt/.env ]; then
|
|
||||||
LE_EMAIL="${LE_EMAIL:-$(grep -E '^LE_EMAIL=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^LE_EMAIL=//')}"
|
|
||||||
PROXY_MODE="${PROXY_MODE:-$(grep -E '^PROXY_MODE=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^PROXY_MODE=//')}"
|
|
||||||
NPM_IP="${NPM_IP:-$(grep -E '^NPM_IP=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^NPM_IP=//')}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Header
|
# ---------- Systemdaten ----------
|
||||||
printf "${CY}"
|
now="$(date '+%Y-%m-%d %H:%M:%S %Z' 2>/dev/null || echo '-')"
|
||||||
cat <<'ASCII'
|
upt="$(uptime -p 2>/dev/null || echo '-')"
|
||||||
:::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: :::::::::::
|
cores="$(nproc 2>/dev/null || echo 1)"
|
||||||
+:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
|
load_raw="$(awk '{printf "%s / %s / %s",$1,$2,$3}' /proc/loadavg 2>/dev/null || echo '0.00 / 0.00 / 0.00')"
|
||||||
+:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
|
load1="$(awk '{print $1}' /proc/loadavg 2>/dev/null || echo 0)"
|
||||||
+#+ +:+ +#+ +#++:++#++: +#+ +#+ +#+ +:+ +#+ +#+ +:+ +#+ +#+
|
|
||||||
+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+
|
|
||||||
#+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+#
|
|
||||||
### ### ### ### ########### ########## ### ### ######## ########## ###
|
|
||||||
ASCII
|
|
||||||
printf "${NC}\n"
|
|
||||||
|
|
||||||
# Safe-Helfer (niemals Script killen)
|
# RAM/SWAP
|
||||||
grab() { eval "$1" 2>/dev/null || true; }
|
mem_total="$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo 0)"
|
||||||
line() { printf "${GY}%-7s:${NC} %s\n" "$1" "$2"; }
|
mem_avail="$(awk '/MemAvailable/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo 0)"
|
||||||
|
mem_used=$(( mem_total - mem_avail ))
|
||||||
|
swap_total="$(awk '/SwapTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo 0)"
|
||||||
|
swap_free="$(awk '/SwapFree/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo 0)"
|
||||||
|
swap_used=$(( swap_total - swap_free ))
|
||||||
|
|
||||||
# Systemdaten
|
pct(){ local u="$1" t="$2"; [ "$t" -gt 0 ] || { echo 0; return; }; awk -v u="$u" -v t="$t" 'BEGIN{printf "%d",(u*100)/t}' ; }
|
||||||
now="$(date '+%Y-%m-%d %H:%M:%S %Z' 2>/dev/null || echo -n '-')"
|
ram_pct=$(pct "$mem_used" "$mem_total")
|
||||||
fqdn="$(hostname -f 2>/dev/null || hostname 2>/dev/null || echo -n '-')"
|
swap_pct=$(pct "$swap_used" "$swap_total")
|
||||||
ip_int="$(hostname -I 2>/dev/null | awk '{print $1}' 2>/dev/null || true)"
|
|
||||||
ip_ext="$(curl -fsS --max-time 1 https://ifconfig.me 2>/dev/null || true)"
|
|
||||||
upt="$(uptime -p 2>/dev/null || echo -n '-')"
|
|
||||||
cores="$(nproc 2>/dev/null || echo -n '-')"
|
|
||||||
load="$(awk '{print $1" / "$2" / "$3}' /proc/loadavg 2>/dev/null || echo -n '-')"
|
|
||||||
|
|
||||||
# RAM/SWAP (MiB)
|
|
||||||
mem_total="$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo -n '-')"
|
|
||||||
mem_avail="$(awk '/MemAvailable/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo -n '0')"
|
|
||||||
mem_used=$(( ${mem_total:-0}-${mem_avail:-0} ))
|
|
||||||
swap_total="$(awk '/SwapTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo -n '-')"
|
|
||||||
swap_free="$(awk '/SwapFree/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo -n '0')"
|
|
||||||
swap_used=$(( ${swap_total:-0}-${swap_free:-0} ))
|
|
||||||
|
|
||||||
# Disks
|
# Disks
|
||||||
disk_line(){ df -hP "$1" 2>/dev/null | awk 'NR==2{printf "%s/%s (%s used)", $3,$2,$5}'; }
|
df_line(){ df -hP "$1" 2>/dev/null | awk 'NR==2{printf "%s / %s (%s)",$3,$2,$5}'; }
|
||||||
disk_root="$(disk_line /)"
|
df_pct(){ df -P "$1" 2>/dev/null | awk 'NR==2{gsub("%","",$5);print $5+0}'; }
|
||||||
disk_var="$(disk_line /var)"
|
disk_root="$(df_line /)"; pct_root="$(df_pct /)"
|
||||||
|
disk_var="$(df_line /var 2>/dev/null)"; [ -n "$disk_var" ] || disk_var="-"
|
||||||
|
pct_var="$(df_pct /var 2>/dev/null)"; [ -n "$pct_var" ] || pct_var=0
|
||||||
|
|
||||||
svc_state(){
|
# IPs (int/ext)
|
||||||
local unit="$1"
|
ipv4_int="$(hostname -I 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i!~/:/){print $i;exit}}')"
|
||||||
if systemctl is-active --quiet "$unit"; then
|
ipv6_int="$(hostname -I 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i~/:/){print $i;exit}}')"
|
||||||
printf "${GR}OK${NC}"
|
ipv4_ext="$(curl -4fsS --max-time 1 https://ifconfig.me 2>/dev/null || true)"
|
||||||
else
|
ipv6_ext="$(curl -6fsS --max-time 1 https://ifconfig.me 2>/dev/null || true)"
|
||||||
printf "${RD}FAIL${NC}"
|
|
||||||
|
# ---------- Status-Farben ----------
|
||||||
|
mark(){ # value thresholdY thresholdR
|
||||||
|
local v="$1" y="$2" r="$3"
|
||||||
|
if [ "$v" -ge "$r" ]; then printf "${RD}[HIGH]${NC}"
|
||||||
|
elif [ "$v" -ge "$y" ]; then printf "${YE}[WARN]${NC}"
|
||||||
|
else printf "${GR}[OK]${NC}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
# Load/CPU-Schwellen (pro Core)
|
||||||
|
load_pct=$(awk -v l="$load1" -v c="$cores" 'BEGIN{if(c<1)c=1; printf "%d", (l/c)*100}')
|
||||||
|
m_load="$(mark "$load_pct" 70 100)"
|
||||||
|
m_ram="$(mark "$ram_pct" 75 90)"
|
||||||
|
m_swap="$(mark "$swap_pct" 10 50)"
|
||||||
|
m_root="$(mark "$pct_root" 75 90)"
|
||||||
|
m_var="$(mark "$pct_var" 75 90)"
|
||||||
|
|
||||||
# Ausgabe
|
# ---------- Header ----------
|
||||||
printf "${CY}Information as of:${NC} ${YE}%s${NC}\n" "$now"
|
rule
|
||||||
line "FQDN" "$fqdn"
|
center ""
|
||||||
if [ -n "$ip_ext" ]; then
|
center ":::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: :::::::::::"
|
||||||
printf "${GY}%-7s:${NC} %s ${GY}(ext:${NC} %s${GY})${NC}\n" "IP" "${ip_int:--}" "$ip_ext"
|
center ":+:+:+ :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: "
|
||||||
else
|
center ":+: +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ "
|
||||||
line "IP" "${ip_int:--}"
|
center "+#+ +:+ +#+ +#++:++#++: +#+ +#+ +#+ +:+ +#+ +#+ +:+ +#+ +#+ "
|
||||||
fi
|
center "+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+ "
|
||||||
line "Uptime" "$upt"
|
center "#+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+# "
|
||||||
printf "${GY}%-7s:${NC} %s cores, load %s (1/5/15)\n" "CPU" "$cores" "$load"
|
center "### ### ### ### ########### ########## ### ### ######## ########## ### "
|
||||||
printf "${GY}%-7s:${NC} %s MiB used / %s MiB total\n" "RAM" "$mem_used" "$mem_total"
|
center ""
|
||||||
printf "${GY}%-7s:${NC} %s MiB used / %s MiB total\n" "SWAP" "$swap_used" "$swap_total"
|
rule
|
||||||
line "Disk /" "${disk_root:-'-'}"
|
|
||||||
line "Disk/var" "${disk_var:-'-'}"
|
|
||||||
|
|
||||||
# App/Installer Infos
|
# ---------- System ----------
|
||||||
[ -n "${LE_EMAIL:-}" ] && line "LE Mail" "$LE_EMAIL"
|
kv "Date / Time" "${YE}${now}${NC}"
|
||||||
[ -n "${UI_HOST:-}" ] && line "UI" "$UI_HOST"
|
sp "$pad"; printf "%-12s: int %-40s ext %s\n" "IPv4" "${ipv4_int:--}" "${ipv4_ext:--}"
|
||||||
[ -n "${WEBMAIL_HOST:-}" ] && line "Webmail" "$WEBMAIL_HOST"
|
sp "$pad"; printf "%-12s: int %-40s ext %s\n" "IPv6" "${ipv6_int:--}" "${ipv6_ext:--}"
|
||||||
[ -n "${MAIL_HOSTNAME:-}" ]&& line "MX" "$MAIL_HOSTNAME"
|
kv "Uptime" "$upt"
|
||||||
if [ -n "${PROXY_MODE:-}" ]; then
|
sp "$pad"; printf "%-12s: %s cores, load %s %b\n" "CPU" "$cores" "$load_raw" "$m_load"
|
||||||
if [ "$PROXY_MODE" = "1" ]; then
|
sp "$pad"; printf "%-12s: %s MiB / %s MiB (%d%%) %b %-5s %s MiB / %s MiB (%d%%) %b\n" \
|
||||||
line "Proxy" "ja (NPM: ${NPM_IP:-unbekannt})"
|
"RAM" "$mem_used" "$mem_total" "$ram_pct" "$m_ram" "SWAP:" "$swap_used" "$swap_total" "$swap_pct" "$m_swap"
|
||||||
elif [ "$PROXY_MODE" = "dev" ]; then
|
sp "$pad"; printf "%-12s: / %s %b %-5s %s %b\n" \
|
||||||
line "Proxy" "Entwicklungsmodus"
|
"Disk" "$disk_root" "$m_root" "/var:" "$disk_var" "$m_var"
|
||||||
else
|
echo
|
||||||
line "Proxy" "nein"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Services
|
# ---------- Domains ----------
|
||||||
printf "${WH}\nServices:${NC}\n"
|
title "Domains"
|
||||||
printf " nginx … %b\n" "$(svc_state nginx)"
|
[ -n "${UI_HOST:-}" ] && kv "UI" "${UI_HOST}"
|
||||||
printf " mariadb … %b\n" "$(svc_state mariadb)"
|
[ -n "${WEBMAIL_HOST:-}" ] && kv "Webmail" "${WEBMAIL_HOST}"
|
||||||
printf " redis-server … %b\n" "$(svc_state redis-server)"
|
[ -n "${MAIL_HOSTNAME:-}" ]&& kv "MX" "${MAIL_HOSTNAME}"
|
||||||
printf " postfix … %b\n" "$(svc_state postfix)"
|
echo
|
||||||
printf " dovecot … %b\n" "$(svc_state dovecot)"
|
|
||||||
printf " mailwolt-ws … %b\n" "$(svc_state mailwolt-ws)"
|
|
||||||
printf " mailwolt-queue … %b\n" "$(svc_state mailwolt-queue)"
|
|
||||||
printf " mailwolt-schedule … %b\n" "$(svc_state mailwolt-schedule)"
|
|
||||||
|
|
||||||
# Zertifikatskurzinfo (nur wenn vorhanden)
|
# ---------- Services (4 Spalten, bündig) ----------
|
||||||
show_cert_exp(){
|
title "Services"
|
||||||
local name="$1" path="$2"
|
svc_state(){ systemctl is-active --quiet "$1" && printf "${GR}[OK]${NC}" || printf "${RD}[FAIL]${NC}"; }
|
||||||
if [ -r "$path" ]; then
|
SVC=( nginx mariadb redis-server postfix dovecot rspamd opendkim opendmarc clamav-daemon fail2ban mailwolt-ws mailwolt-queue mailwolt-schedule )
|
||||||
local exp
|
|
||||||
exp="$(openssl x509 -in "$path" -noout -enddate 2>/dev/null | sed 's/notAfter=//')"
|
i=0; line=""
|
||||||
[ -n "$exp" ] && printf "${GY}%s cert:${NC} expires %s\n" "$name" "$exp"
|
for s in "${SVC[@]}"; do
|
||||||
fi
|
st="$(svc_state "$s")"
|
||||||
}
|
seg="$(printf "%-18s %-7s" "$s" "$st")"
|
||||||
show_cert_exp "UI" "/etc/ssl/ui/fullchain.pem"
|
line="$line$seg"
|
||||||
show_cert_exp "Webmail" "/etc/ssl/webmail/fullchain.pem"
|
i=$((i+1))
|
||||||
show_cert_exp "MX" "/etc/ssl/mail/fullchain.pem"
|
if [ $((i%4)) -eq 0 ]; then sp "$pad"; echo "$line"; line=""; else line="$line "; fi
|
||||||
|
done
|
||||||
|
[ -n "$line" ] && { sp "$pad"; echo "$line"; }
|
||||||
|
echo
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
SH
|
SH
|
||||||
|
|
||||||
chmod 755 /usr/local/bin/mw-motd
|
chmod 755 /usr/local/bin/mw-motd
|
||||||
|
|
||||||
|
# update-motd Hook
|
||||||
if [[ -d /etc/update-motd.d ]]; then
|
if [[ -d /etc/update-motd.d ]]; then
|
||||||
cat >/etc/update-motd.d/10-mailwolt <<'SH'
|
cat >/etc/update-motd.d/10-mailwolt <<'SH'
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
@ -136,47 +140,21 @@ SH
|
||||||
chmod +x /etc/update-motd.d/10-mailwolt
|
chmod +x /etc/update-motd.d/10-mailwolt
|
||||||
[[ -f /etc/update-motd.d/50-motd-news ]] && chmod -x /etc/update-motd.d/50-motd-news || true
|
[[ -f /etc/update-motd.d/50-motd-news ]] && chmod -x /etc/update-motd.d/50-motd-news || true
|
||||||
else
|
else
|
||||||
|
# Fallback für Systeme ohne dynamic MOTD
|
||||||
cat >/etc/profile.d/10-mailwolt-motd.sh <<'SH'
|
cat >/etc/profile.d/10-mailwolt-motd.sh <<'SH'
|
||||||
case "$-" in *i*) /usr/local/bin/mw-motd ;; esac
|
case "$-" in *i*) /usr/local/bin/mw-motd ;; esac
|
||||||
SH
|
SH
|
||||||
fi
|
fi
|
||||||
|
|
||||||
: > /etc/motd 2>/dev/null || true
|
: > /etc/motd 2>/dev/null || true
|
||||||
|
log "[✓] MOTD installiert."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#cat >/usr/local/bin/mw-motd <<'SH'
|
|
||||||
##!/usr/bin/env bash
|
##!/usr/bin/env bash
|
||||||
#set -euo pipefail
|
#set -euo pipefail
|
||||||
#NC="\033[0m"; CY="\033[1;36m"; GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m"; GY="\033[0;90m"
|
#source ./lib.sh
|
||||||
#printf "\033[1;36m"
|
#
|
||||||
#cat <<'ASCII'
|
#log "MOTD installieren …"
|
||||||
#:::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: :::::::::::
|
#install -d /usr/local/bin
|
||||||
#+:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
|
|
||||||
#+:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
|
|
||||||
#+#+ +:+ +#+ +#++:++#++: +#+ +#+ +#+ +:+ +#+ +#+ +:+ +#+ +#+
|
|
||||||
#+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+
|
|
||||||
##+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+#
|
|
||||||
#### ### ### ### ########### ########## ### ### ######## ########## ###
|
|
||||||
#ASCII
|
|
||||||
#printf "\033[0m\n"
|
|
||||||
#now="$(date '+%Y-%m-%d %H:%M:%S %Z')"
|
|
||||||
#fqdn="$(hostname -f 2>/dev/null || hostname)"
|
|
||||||
#ip_int="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
|
||||||
#ip_ext=""; command -v curl >/dev/null 2>&1 && ip_ext="$(curl -s --max-time 1 https://ifconfig.me || true)"
|
|
||||||
#upt="$(uptime -p 2>/dev/null || true)"
|
|
||||||
#cores="$(nproc 2>/dev/null || echo -n '?')"
|
|
||||||
#load="$(awk '{print $1" / "$2" / "$3}' /proc/loadavg 2>/dev/null)"
|
|
||||||
#svc(){ systemctl is-active --quiet "$1" && echo -e "${GR}OK${NC}" || echo -e "${RD}FAIL${NC}"; }
|
|
||||||
#printf "${CY}Information as of:${NC} ${YE}%s${NC}\n" "$now"
|
|
||||||
#printf "${GY}FQDN :${NC} %s\n" "$fqdn"
|
|
||||||
#if [ -n "$ip_ext" ]; then printf "${GY}IP :${NC} %s ${GY}(ext:${NC} %s${GY})${NC}\n" "${ip_int:-?}" "$ip_ext"; else printf "${GY}IP :${NC} %s\n" "${ip_int:-?}"; fi
|
|
||||||
#printf "${GY}Uptime :${NC} %s\n" "${upt:-?}"
|
|
||||||
#printf "${GY}Cores :${NC} %s\n" "$cores"
|
|
||||||
#printf "${GY}Load :${NC} %s (1/5/15)\n" "${load:-?}"
|
|
||||||
#printf "${GY}Svc :${NC} postfix: $(svc postfix) dovecot: $(svc dovecot) nginx: $(svc nginx) mariadb: $(svc mariadb) redis: $(svc redis)\n"
|
|
||||||
#SH
|
|
||||||
#chmod +x /usr/local/bin/mw-motd
|
|
||||||
|
|
||||||
#cat >/usr/local/bin/mw-motd <<'SH'
|
#cat >/usr/local/bin/mw-motd <<'SH'
|
||||||
##!/usr/bin/env bash
|
##!/usr/bin/env bash
|
||||||
## bewusst KEIN "set -e"; MOTD soll nie hart abbrechen
|
## bewusst KEIN "set -e"; MOTD soll nie hart abbrechen
|
||||||
|
|
@ -198,6 +176,9 @@ fi
|
||||||
## Header
|
## Header
|
||||||
#printf "${CY}"
|
#printf "${CY}"
|
||||||
#cat <<'ASCII'
|
#cat <<'ASCII'
|
||||||
|
#
|
||||||
|
#==========================================================================================
|
||||||
|
#
|
||||||
#:::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: :::::::::::
|
#:::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: :::::::::::
|
||||||
#+:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
|
#+:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
|
||||||
#+:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
|
#+:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
|
||||||
|
|
@ -205,6 +186,9 @@ fi
|
||||||
#+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+
|
#+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+
|
||||||
##+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+#
|
##+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+#
|
||||||
#### ### ### ### ########### ########## ### ### ######## ########## ###
|
#### ### ### ### ########### ########## ### ### ######## ########## ###
|
||||||
|
#
|
||||||
|
#==========================================================================================
|
||||||
|
#
|
||||||
#ASCII
|
#ASCII
|
||||||
#printf "${NC}\n"
|
#printf "${NC}\n"
|
||||||
#
|
#
|
||||||
|
|
@ -299,4 +283,177 @@ fi
|
||||||
#
|
#
|
||||||
#exit 0
|
#exit 0
|
||||||
#SH
|
#SH
|
||||||
#chmod 755 /usr/local/bin/mw-motd
|
#chmod 755 /usr/local/bin/mw-motd
|
||||||
|
#
|
||||||
|
#if [[ -d /etc/update-motd.d ]]; then
|
||||||
|
# cat >/etc/update-motd.d/10-mailwolt <<'SH'
|
||||||
|
##!/usr/bin/env bash
|
||||||
|
#/usr/local/bin/mw-motd
|
||||||
|
#SH
|
||||||
|
# chmod +x /etc/update-motd.d/10-mailwolt
|
||||||
|
# [[ -f /etc/update-motd.d/50-motd-news ]] && chmod -x /etc/update-motd.d/50-motd-news || true
|
||||||
|
#else
|
||||||
|
# cat >/etc/profile.d/10-mailwolt-motd.sh <<'SH'
|
||||||
|
#case "$-" in *i*) /usr/local/bin/mw-motd ;; esac
|
||||||
|
#SH
|
||||||
|
#fi
|
||||||
|
#: > /etc/motd 2>/dev/null || true
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
##cat >/usr/local/bin/mw-motd <<'SH'
|
||||||
|
###!/usr/bin/env bash
|
||||||
|
##set -euo pipefail
|
||||||
|
##NC="\033[0m"; CY="\033[1;36m"; GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m"; GY="\033[0;90m"
|
||||||
|
##printf "\033[1;36m"
|
||||||
|
##cat <<'ASCII'
|
||||||
|
##:::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: :::::::::::
|
||||||
|
##+:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
|
||||||
|
##+:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
|
||||||
|
##+#+ +:+ +#+ +#++:++#++: +#+ +#+ +#+ +:+ +#+ +#+ +:+ +#+ +#+
|
||||||
|
##+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+
|
||||||
|
###+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+#
|
||||||
|
##### ### ### ### ########### ########## ### ### ######## ########## ###
|
||||||
|
##ASCII
|
||||||
|
##printf "\033[0m\n"
|
||||||
|
##now="$(date '+%Y-%m-%d %H:%M:%S %Z')"
|
||||||
|
##fqdn="$(hostname -f 2>/dev/null || hostname)"
|
||||||
|
##ip_int="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||||
|
##ip_ext=""; command -v curl >/dev/null 2>&1 && ip_ext="$(curl -s --max-time 1 https://ifconfig.me || true)"
|
||||||
|
##upt="$(uptime -p 2>/dev/null || true)"
|
||||||
|
##cores="$(nproc 2>/dev/null || echo -n '?')"
|
||||||
|
##load="$(awk '{print $1" / "$2" / "$3}' /proc/loadavg 2>/dev/null)"
|
||||||
|
##svc(){ systemctl is-active --quiet "$1" && echo -e "${GR}OK${NC}" || echo -e "${RD}FAIL${NC}"; }
|
||||||
|
##printf "${CY}Information as of:${NC} ${YE}%s${NC}\n" "$now"
|
||||||
|
##printf "${GY}FQDN :${NC} %s\n" "$fqdn"
|
||||||
|
##if [ -n "$ip_ext" ]; then printf "${GY}IP :${NC} %s ${GY}(ext:${NC} %s${GY})${NC}\n" "${ip_int:-?}" "$ip_ext"; else printf "${GY}IP :${NC} %s\n" "${ip_int:-?}"; fi
|
||||||
|
##printf "${GY}Uptime :${NC} %s\n" "${upt:-?}"
|
||||||
|
##printf "${GY}Cores :${NC} %s\n" "$cores"
|
||||||
|
##printf "${GY}Load :${NC} %s (1/5/15)\n" "${load:-?}"
|
||||||
|
##printf "${GY}Svc :${NC} postfix: $(svc postfix) dovecot: $(svc dovecot) nginx: $(svc nginx) mariadb: $(svc mariadb) redis: $(svc redis)\n"
|
||||||
|
##SH
|
||||||
|
##chmod +x /usr/local/bin/mw-motd
|
||||||
|
#
|
||||||
|
##cat >/usr/local/bin/mw-motd <<'SH'
|
||||||
|
###!/usr/bin/env bash
|
||||||
|
### bewusst KEIN "set -e"; MOTD soll nie hart abbrechen
|
||||||
|
##set -u
|
||||||
|
##
|
||||||
|
### Farben
|
||||||
|
##NC="\033[0m"; CY="\033[1;36m"; GR="\033[1;32m"; YE="\033[1;33m"; RD="\033[1;31m"; GY="\033[0;90m"; WH="\033[1;37m"
|
||||||
|
##
|
||||||
|
### Installer-Variablen (optional)
|
||||||
|
##UI_HOST=""; WEBMAIL_HOST=""; MAIL_HOSTNAME=""; LE_EMAIL=""; PROXY_MODE=""; NPM_IP=""
|
||||||
|
##[ -r /etc/mailwolt/installer.env ] && . /etc/mailwolt/installer.env || true
|
||||||
|
### Aus .env (falls vorhanden)
|
||||||
|
##if [ -r /var/www/mailwolt/.env ]; then
|
||||||
|
## LE_EMAIL="${LE_EMAIL:-$(grep -E '^LE_EMAIL=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^LE_EMAIL=//')}"
|
||||||
|
## PROXY_MODE="${PROXY_MODE:-$(grep -E '^PROXY_MODE=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^PROXY_MODE=//')}"
|
||||||
|
## NPM_IP="${NPM_IP:-$(grep -E '^NPM_IP=' /var/www/mailwolt/.env 2>/dev/null | sed 's/^NPM_IP=//')}"
|
||||||
|
##fi
|
||||||
|
##
|
||||||
|
### Header
|
||||||
|
##printf "${CY}"
|
||||||
|
##cat <<'ASCII'
|
||||||
|
##:::: :::: ::: ::::::::::: ::: ::: ::: :::::::: ::: :::::::::::
|
||||||
|
##+:+:+: :+:+:+ :+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
|
||||||
|
##+:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
|
||||||
|
##+#+ +:+ +#+ +#++:++#++: +#+ +#+ +#+ +:+ +#+ +#+ +:+ +#+ +#+
|
||||||
|
##+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+ +#+
|
||||||
|
###+# #+# #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+# #+#
|
||||||
|
##### ### ### ### ########### ########## ### ### ######## ########## ###
|
||||||
|
##ASCII
|
||||||
|
##printf "${NC}\n"
|
||||||
|
##
|
||||||
|
### Safe-Helfer (niemals Script killen)
|
||||||
|
##grab() { eval "$1" 2>/dev/null || true; }
|
||||||
|
##line() { printf "${GY}%-7s:${NC} %s\n" "$1" "$2"; }
|
||||||
|
##
|
||||||
|
### Systemdaten
|
||||||
|
##now="$(date '+%Y-%m-%d %H:%M:%S %Z' 2>/dev/null || echo -n '-')"
|
||||||
|
##fqdn="$(hostname -f 2>/dev/null || hostname 2>/dev/null || echo -n '-')"
|
||||||
|
##ip_int="$(hostname -I 2>/dev/null | awk '{print $1}' 2>/dev/null || true)"
|
||||||
|
##ip_ext="$(curl -fsS --max-time 1 https://ifconfig.me 2>/dev/null || true)"
|
||||||
|
##upt="$(uptime -p 2>/dev/null || echo -n '-')"
|
||||||
|
##cores="$(nproc 2>/dev/null || echo -n '-')"
|
||||||
|
##load="$(awk '{print $1" / "$2" / "$3}' /proc/loadavg 2>/dev/null || echo -n '-')"
|
||||||
|
##
|
||||||
|
### RAM/SWAP (MiB)
|
||||||
|
##mem_total="$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo -n '-')"
|
||||||
|
##mem_avail="$(awk '/MemAvailable/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo -n '0')"
|
||||||
|
##mem_used=$(( ${mem_total:-0}-${mem_avail:-0} ))
|
||||||
|
##swap_total="$(awk '/SwapTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo -n '-')"
|
||||||
|
##swap_free="$(awk '/SwapFree/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo -n '0')"
|
||||||
|
##swap_used=$(( ${swap_total:-0}-${swap_free:-0} ))
|
||||||
|
##
|
||||||
|
### Disks
|
||||||
|
##disk_line(){ df -hP "$1" 2>/dev/null | awk 'NR==2{printf "%s/%s (%s used)", $3,$2,$5}'; }
|
||||||
|
##disk_root="$(disk_line /)"
|
||||||
|
##disk_var="$(disk_line /var)"
|
||||||
|
##
|
||||||
|
##svc_state(){
|
||||||
|
## local unit="$1"
|
||||||
|
## if systemctl is-active --quiet "$unit"; then
|
||||||
|
## printf "${GR}OK${NC}"
|
||||||
|
## else
|
||||||
|
## printf "${RD}FAIL${NC}"
|
||||||
|
## fi
|
||||||
|
##}
|
||||||
|
##
|
||||||
|
### Ausgabe
|
||||||
|
##printf "${CY}Information as of:${NC} ${YE}%s${NC}\n" "$now"
|
||||||
|
##line "FQDN" "$fqdn"
|
||||||
|
##if [ -n "$ip_ext" ]; then
|
||||||
|
## printf "${GY}%-7s:${NC} %s ${GY}(ext:${NC} %s${GY})${NC}\n" "IP" "${ip_int:--}" "$ip_ext"
|
||||||
|
##else
|
||||||
|
## line "IP" "${ip_int:--}"
|
||||||
|
##fi
|
||||||
|
##line "Uptime" "$upt"
|
||||||
|
##printf "${GY}%-7s:${NC} %s cores, load %s (1/5/15)\n" "CPU" "$cores" "$load"
|
||||||
|
##printf "${GY}%-7s:${NC} %s MiB used / %s MiB total\n" "RAM" "$mem_used" "$mem_total"
|
||||||
|
##printf "${GY}%-7s:${NC} %s MiB used / %s MiB total\n" "SWAP" "$swap_used" "$swap_total"
|
||||||
|
##line "Disk /" "${disk_root:-'-'}"
|
||||||
|
##line "Disk/var" "${disk_var:-'-'}"
|
||||||
|
##
|
||||||
|
### App/Installer Infos
|
||||||
|
##[ -n "${LE_EMAIL:-}" ] && line "LE Mail" "$LE_EMAIL"
|
||||||
|
##[ -n "${UI_HOST:-}" ] && line "UI" "$UI_HOST"
|
||||||
|
##[ -n "${WEBMAIL_HOST:-}" ] && line "Webmail" "$WEBMAIL_HOST"
|
||||||
|
##[ -n "${MAIL_HOSTNAME:-}" ]&& line "MX" "$MAIL_HOSTNAME"
|
||||||
|
##if [ -n "${PROXY_MODE:-}" ]; then
|
||||||
|
## if [ "$PROXY_MODE" = "1" ]; then
|
||||||
|
## line "Proxy" "ja (NPM: ${NPM_IP:-unbekannt})"
|
||||||
|
## elif [ "$PROXY_MODE" = "dev" ]; then
|
||||||
|
## line "Proxy" "Entwicklungsmodus"
|
||||||
|
## else
|
||||||
|
## line "Proxy" "nein"
|
||||||
|
## fi
|
||||||
|
##fi
|
||||||
|
##
|
||||||
|
### Services
|
||||||
|
##printf "${WH}\nServices:${NC}\n"
|
||||||
|
##printf " nginx … %b\n" "$(svc_state nginx)"
|
||||||
|
##printf " mariadb … %b\n" "$(svc_state mariadb)"
|
||||||
|
##printf " redis-server … %b\n" "$(svc_state redis-server)"
|
||||||
|
##printf " postfix … %b\n" "$(svc_state postfix)"
|
||||||
|
##printf " dovecot … %b\n" "$(svc_state dovecot)"
|
||||||
|
##printf " mailwolt-ws … %b\n" "$(svc_state mailwolt-ws)"
|
||||||
|
##printf " mailwolt-queue … %b\n" "$(svc_state mailwolt-queue)"
|
||||||
|
##printf " mailwolt-schedule … %b\n" "$(svc_state mailwolt-schedule)"
|
||||||
|
##
|
||||||
|
### Zertifikatskurzinfo (nur wenn vorhanden)
|
||||||
|
##show_cert_exp(){
|
||||||
|
## local name="$1" path="$2"
|
||||||
|
## if [ -r "$path" ]; then
|
||||||
|
## local exp
|
||||||
|
## exp="$(openssl x509 -in "$path" -noout -enddate 2>/dev/null | sed 's/notAfter=//')"
|
||||||
|
## [ -n "$exp" ] && printf "${GY}%s cert:${NC} expires %s\n" "$name" "$exp"
|
||||||
|
## fi
|
||||||
|
##}
|
||||||
|
##show_cert_exp "UI" "/etc/ssl/ui/fullchain.pem"
|
||||||
|
##show_cert_exp "Webmail" "/etc/ssl/webmail/fullchain.pem"
|
||||||
|
##show_cert_exp "MX" "/etc/ssl/mail/fullchain.pem"
|
||||||
|
##
|
||||||
|
##exit 0
|
||||||
|
##SH
|
||||||
|
##chmod 755 /usr/local/bin/mw-motd
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# --- Flags / Modi ---
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
# MailWolt – Interaktiver Bootstrap (whiptail + Fallback)
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
DEV_MODE=0
|
DEV_MODE=0
|
||||||
PROXY_MODE=0
|
PROXY_MODE=0
|
||||||
NPM_IP=""
|
NPM_IP=""
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-dev) DEV_MODE=1 ;;
|
-dev) DEV_MODE=1 ;;
|
||||||
|
|
@ -15,12 +17,11 @@ while [[ $# -gt 0 ]]; do
|
||||||
done
|
done
|
||||||
|
|
||||||
APP_ENV="${APP_ENV:-$([[ $DEV_MODE -eq 1 ]] && echo local || echo production)}"
|
APP_ENV="${APP_ENV:-$([[ $DEV_MODE -eq 1 ]] && echo local || echo production)}"
|
||||||
APP_DEBUG="${APP_DEBUG:-$([[ $DEV_MODE -eq 1 ]] && echo true || echo false)}"
|
APP_DEBUG="${APP_DEBUG:-$([[ $DEV_MODE -eq 1 ]] && echo true || echo false)}"
|
||||||
export DEV_MODE PROXY_MODE NPM_IP APP_ENV APP_DEBUG
|
export DEV_MODE PROXY_MODE NPM_IP APP_ENV APP_DEBUG
|
||||||
|
|
||||||
DB_PASS="${DB_PASS:-$(openssl rand -hex 16)}"
|
DB_PASS="${DB_PASS:-$(openssl rand -hex 16)}"
|
||||||
REDIS_PASS="${REDIS_PASS:-$(openssl rand -hex 16)}"
|
REDIS_PASS="${REDIS_PASS:-$(openssl rand -hex 16)}"
|
||||||
|
|
||||||
export DB_PASS REDIS_PASS
|
export DB_PASS REDIS_PASS
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
|
|
@ -28,7 +29,7 @@ source ./lib.sh
|
||||||
require_root
|
require_root
|
||||||
header
|
header
|
||||||
|
|
||||||
# ── Defaults ────────────────────────────────────────────────────────────────
|
# ── Defaults ──────────────────────────────────────────────────
|
||||||
APP_NAME="${APP_NAME:-MailWolt}"
|
APP_NAME="${APP_NAME:-MailWolt}"
|
||||||
APP_USER="${APP_USER:-mailwolt}"
|
APP_USER="${APP_USER:-mailwolt}"
|
||||||
APP_GROUP="${APP_GROUP:-www-data}"
|
APP_GROUP="${APP_GROUP:-www-data}"
|
||||||
|
|
@ -50,49 +51,109 @@ DEFAULT_LOCALE="$(guess_locale_from_tz "$DEFAULT_TZ")"
|
||||||
|
|
||||||
echo -e "${GREY}Erkannte IP (v4): ${SERVER_PUBLIC_IPV4} v6: ${SERVER_PUBLIC_IPV6:-–}${NC}"
|
echo -e "${GREY}Erkannte IP (v4): ${SERVER_PUBLIC_IPV4} v6: ${SERVER_PUBLIC_IPV6:-–}${NC}"
|
||||||
|
|
||||||
# ── FQDNs abfragen ───────────────────────────────────────────────────────────
|
# ── Helpers ───────────────────────────────────────────────────
|
||||||
read -r -p "Mailserver FQDN (MX, z.B. mx.domain.tld) [Enter=${MTA_SUB}.${BASE_DOMAIN}]: " MTA_FQDN
|
have_whiptail(){ command -v whiptail >/dev/null 2>&1; }
|
||||||
read -r -p "UI / Admin-Panel FQDN (z.B. ui.domain.tld) [Enter=${UI_SUB}.${BASE_DOMAIN}]: " UI_FQDN
|
valid_fqdn(){
|
||||||
read -r -p "Webmail FQDN (z.B. webmail.domain.tld) [Enter=${WEBMAIL_SUB}.${BASE_DOMAIN}]: " WEBMAIL_FQDN
|
[[ "$1" =~ ^([a-z0-9]([-a-z0-9]*[a-z0-9])?\.)+[a-z]{2,}$ ]]
|
||||||
|
}
|
||||||
|
ask_tty_domain(){
|
||||||
|
local label="$1" example="$2" def="$3" outvar="$4" inp
|
||||||
|
echo -e "${CYAN}${label}${NC}"
|
||||||
|
echo -e " z.B. ${YELLOW}${example}${NC}"
|
||||||
|
echo -e " Default: ${GREY}${def}${NC}"
|
||||||
|
read -r -p " Eingabe (Enter=Default): " inp || true
|
||||||
|
inp="${inp:-$def}"
|
||||||
|
if ! valid_fqdn "$inp"; then
|
||||||
|
echo -e "${YELLOW}[!] Ungültiger FQDN, nehme Default: ${def}${NC}"
|
||||||
|
inp="$def"
|
||||||
|
fi
|
||||||
|
eval "$outvar='$inp'"
|
||||||
|
}
|
||||||
|
|
||||||
# Defaults, wenn Enter gedrückt
|
# ── Interaktive Eingaben (whiptail oder Fallback) ─────────────
|
||||||
MTA_FQDN="${MTA_FQDN:-${MTA_SUB}.${BASE_DOMAIN}}"
|
MTA_DEFAULT="${MTA_SUB}.${BASE_DOMAIN}"
|
||||||
UI_FQDN="${UI_FQDN:-${UI_SUB}.${BASE_DOMAIN}}"
|
UI_DEFAULT="${UI_SUB}.${BASE_DOMAIN}"
|
||||||
WEBMAIL_FQDN="${WEBMAIL_FQDN:-${WEBMAIL_SUB}.${BASE_DOMAIN}}"
|
WEBMAIL_DEFAULT="${WEBMAIL_SUB}.${BASE_DOMAIN}"
|
||||||
|
|
||||||
|
CLAMAV_ENABLE=1
|
||||||
|
OPENDMARC_ENABLE=1
|
||||||
|
FAIL2BAN_ENABLE=1
|
||||||
|
|
||||||
|
if have_whiptail; then
|
||||||
|
TITLE="MailWolt Setup"
|
||||||
|
|
||||||
|
MTA_FQDN="$(whiptail --title "$TITLE" --inputbox "Mailserver-FQDN (MX)\nBeispiel: mx.domain.tld" 11 70 "$MTA_DEFAULT" 3>&1 1>&2 2>&3)" || exit 1
|
||||||
|
valid_fqdn "$MTA_FQDN" || MTA_FQDN="$MTA_DEFAULT"
|
||||||
|
|
||||||
|
UI_FQDN="$(whiptail --title "$TITLE" --inputbox "UI / Admin-Panel FQDN\nBeispiel: ui.domain.tld" 11 70 "$UI_DEFAULT" 3>&1 1>&2 2>&3)" || exit 1
|
||||||
|
valid_fqdn "$UI_FQDN" || UI_FQDN="$UI_DEFAULT"
|
||||||
|
|
||||||
|
WEBMAIL_FQDN="$(whiptail --title "$TITLE" --inputbox "Webmail FQDN\nBeispiel: webmail.domain.tld" 11 70 "$WEBMAIL_DEFAULT" 3>&1 1>&2 2>&3)" || exit 1
|
||||||
|
valid_fqdn "$WEBMAIL_FQDN" || WEBMAIL_FQDN="$WEBMAIL_DEFAULT"
|
||||||
|
|
||||||
|
CHOICES="$(whiptail --title "$TITLE" --checklist "Optionale Dienste aktivieren" 15 70 6 \
|
||||||
|
"ClamAV" "Virenscan (clamd/clamav-daemon)" ON \
|
||||||
|
"OpenDMARC" "DMARC-Auswertung" ON \
|
||||||
|
"Fail2Ban" "Brute-Force-Schutz" ON \
|
||||||
|
3>&1 1>&2 2>&3)" || true
|
||||||
|
|
||||||
|
CLAMAV_ENABLE=0; [[ "$CHOICES" == *"ClamAV"* ]] && CLAMAV_ENABLE=1
|
||||||
|
OPENDMARC_ENABLE=0; [[ "$CHOICES" == *"OpenDMARC"* ]] && OPENDMARC_ENABLE=1
|
||||||
|
FAIL2BAN_ENABLE=0; [[ "$CHOICES" == *"Fail2Ban"* ]] && FAIL2BAN_ENABLE=1
|
||||||
|
|
||||||
|
whiptail --title "$TITLE" --msgbox "Zusammenfassung:
|
||||||
|
|
||||||
|
MX : $MTA_FQDN
|
||||||
|
UI : $UI_FQDN
|
||||||
|
Webmail : $WEBMAIL_FQDN
|
||||||
|
|
||||||
|
ClamAV : $([[ $CLAMAV_ENABLE -eq 1 ]] && echo Aktiv || echo Deaktiv)
|
||||||
|
OpenDMARC : $([[ $OPENDMARC_ENABLE -eq 1 ]] && echo Aktiv || echo Deaktiv)
|
||||||
|
Fail2Ban : $([[ $FAIL2BAN_ENABLE -eq 1 ]] && echo Aktiv || echo Deaktiv)
|
||||||
|
" 16 70
|
||||||
|
|
||||||
|
else
|
||||||
|
echo -e "${GREY}[i] whiptail nicht gefunden – nutze TTY-Prompts.${NC}\n"
|
||||||
|
ask_tty_domain "Mailserver-FQDN (MX)" "mx.domain.tld" "$MTA_DEFAULT" MTA_FQDN
|
||||||
|
ask_tty_domain "UI / Admin-Panel FQDN" "ui.domain.tld" "$UI_DEFAULT" UI_FQDN
|
||||||
|
ask_tty_domain "Webmail FQDN" "webmail.domain.tld" "$WEBMAIL_DEFAULT" WEBMAIL_FQDN
|
||||||
|
|
||||||
|
read -r -p "ClamAV aktivieren? (1/0, Enter=1): " CLAMAV_ENABLE; CLAMAV_ENABLE="${CLAMAV_ENABLE:-1}"
|
||||||
|
read -r -p "OpenDMARC aktivieren? (1/0, Enter=1): " OPENDMARC_ENABLE; OPENDMARC_ENABLE="${OPENDMARC_ENABLE:-1}"
|
||||||
|
read -r -p "Fail2Ban aktivieren? (1/0, Enter=1): " FAIL2BAN_ENABLE; FAIL2BAN_ENABLE="${FAIL2BAN_ENABLE:-1}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Defaults/Kompatibilität ──────────────────────────────────
|
||||||
|
MTA_FQDN="${MTA_FQDN:-${MTA_DEFAULT}}"
|
||||||
|
UI_FQDN="${UI_FQDN:-${UI_DEFAULT}}"
|
||||||
|
WEBMAIL_FQDN="${WEBMAIL_FQDN:-${WEBMAIL_DEFAULT}}"
|
||||||
DKIM_ENABLE="${DKIM_ENABLE:-1}"
|
DKIM_ENABLE="${DKIM_ENABLE:-1}"
|
||||||
DKIM_SELECTOR="${DKIM_SELECTOR:-mwl1}"
|
DKIM_SELECTOR="${DKIM_SELECTOR:-mwl1}"
|
||||||
DKIM_GENERATE="${DKIM_GENERATE:-1}"
|
DKIM_GENERATE="${DKIM_GENERATE:-1}"
|
||||||
|
|
||||||
# BASE_DOMAIN und Sub-Labels aus MTA/UI/WEBMAIL ableiten (robust)
|
# BASE_DOMAIN/Subs aus FQDNs ableiten
|
||||||
if [[ "$MTA_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
if [[ "$MTA_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then MTA_SUB="${BASH_REMATCH[1]}"; BASE_DOMAIN="${BASH_REMATCH[2]}"; fi
|
||||||
MTA_SUB="${BASH_REMATCH[1]}"
|
if [[ "$UI_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then UI_SUB="${BASH_REMATCH[1]}"; fi
|
||||||
BASE_DOMAIN="${BASH_REMATCH[2]}"
|
if [[ "$WEBMAIL_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then WEBMAIL_SUB="${BASH_REMATCH[1]}"; fi
|
||||||
fi
|
|
||||||
if [[ "$UI_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
|
||||||
UI_SUB="${BASH_REMATCH[1]}"
|
|
||||||
fi
|
|
||||||
if [[ "$WEBMAIL_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
|
||||||
WEBMAIL_SUB="${BASH_REMATCH[1]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
SYSMAIL_SUB="${SYSMAIL_SUB:-sysmail}"
|
SYSMAIL_SUB="${SYSMAIL_SUB:-sysmail}"
|
||||||
SYSMAIL_DOMAIN="${SYSMAIL_SUB}.${BASE_DOMAIN}"
|
SYSMAIL_DOMAIN="${SYSMAIL_SUB}.${BASE_DOMAIN}"
|
||||||
# Kanonische Host-Variablen (NIE wieder zusammenbauen – nimm die FQDNs)
|
|
||||||
MAIL_HOSTNAME="${MTA_FQDN}"
|
MAIL_HOSTNAME="${MTA_FQDN}"
|
||||||
UI_HOST="${UI_FQDN}"
|
UI_HOST="${UI_FQDN}"
|
||||||
WEBMAIL_HOST="${WEBMAIL_FQDN}"
|
WEBMAIL_HOST="${WEBMAIL_FQDN}"
|
||||||
|
|
||||||
# Zeitzone/Locale sinnvoll setzen (könntest du auch noch abfragen)
|
|
||||||
APP_TZ="${APP_TZ:-$DEFAULT_TZ}"
|
APP_TZ="${APP_TZ:-$DEFAULT_TZ}"
|
||||||
APP_LOCALE="${APP_LOCALE:-$DEFAULT_LOCALE}"
|
APP_LOCALE="${APP_LOCALE:-$DEFAULT_LOCALE}"
|
||||||
|
|
||||||
# ── Variablen exportieren ───────────────────────────────────────────────────
|
# ── Export & persist ─────────────────────────────────────────
|
||||||
export APP_NAME APP_USER APP_GROUP APP_USER_PREFIX APP_DIR
|
export APP_NAME APP_USER APP_GROUP APP_USER_PREFIX APP_DIR
|
||||||
export BASE_DOMAIN UI_SUB WEBMAIL_SUB MTA_SUB
|
export BASE_DOMAIN UI_SUB WEBMAIL_SUB MTA_SUB
|
||||||
export SYSMAIL_SUB SYSMAIL_DOMAIN DKIM_ENABLE DKIM_SELECTOR DKIM_GENERATE
|
export SYSMAIL_SUB SYSMAIL_DOMAIN DKIM_ENABLE DKIM_SELECTOR DKIM_GENERATE
|
||||||
export UI_HOST WEBMAIL_HOST MAIL_HOSTNAME
|
export UI_HOST WEBMAIL_HOST MAIL_HOSTNAME
|
||||||
export DB_NAME DB_USER
|
export DB_NAME DB_USER
|
||||||
export SERVER_PUBLIC_IPV4 SERVER_PUBLIC_IPV6 APP_TZ APP_LOCALE
|
export SERVER_PUBLIC_IPV4 SERVER_PUBLIC_IPV6 APP_TZ APP_LOCALE
|
||||||
|
export CLAMAV_ENABLE OPENDMARC_ENABLE FAIL2BAN_ENABLE
|
||||||
|
|
||||||
install -d -m 0755 /etc/mailwolt
|
install -d -m 0755 /etc/mailwolt
|
||||||
cat >/etc/mailwolt/installer.env <<EOF
|
cat >/etc/mailwolt/installer.env <<EOF
|
||||||
|
|
@ -116,15 +177,350 @@ DB_HOST=127.0.0.1
|
||||||
DB_NAME=${DB_NAME}
|
DB_NAME=${DB_NAME}
|
||||||
DB_USER=${DB_USER}
|
DB_USER=${DB_USER}
|
||||||
DB_PASS=${DB_PASS}
|
DB_PASS=${DB_PASS}
|
||||||
|
REDIS_PASS=${REDIS_PASS}
|
||||||
|
|
||||||
SERVER_PUBLIC_IPV4=${SERVER_PUBLIC_IPV4}
|
SERVER_PUBLIC_IPV4=${SERVER_PUBLIC_IPV4}
|
||||||
SERVER_PUBLIC_IPV6=${SERVER_PUBLIC_IPV6}
|
SERVER_PUBLIC_IPV6=${SERVER_PUBLIC_IPV6}
|
||||||
APP_ENV=${APP_ENV}
|
APP_ENV=${APP_ENV}
|
||||||
EOF
|
|
||||||
|
|
||||||
# ── Sequenz ────────────────────────────────────────────────────────────────
|
CLAMAV_ENABLE=${CLAMAV_ENABLE}
|
||||||
for STEP in 10-provision 20-ssl 21-le-deploy-hook 22-dkim-helper 30-db 40-postfix 50-dovecot 60-rspamd-opendkim 70-nginx 75-le-issue 80-app 90-services 95-monit 98-motd 99-summary
|
OPENDMARC_ENABLE=${OPENDMARC_ENABLE}
|
||||||
|
FAIL2BAN_ENABLE=${FAIL2BAN_ENABLE}
|
||||||
|
EOF
|
||||||
|
chmod 600 /etc/mailwolt/installer.env
|
||||||
|
|
||||||
|
# ── Installer-Sequenz ────────────────────────────────────────
|
||||||
|
for STEP in \
|
||||||
|
10-provision \
|
||||||
|
20-ssl 21-le-deploy-hook 22-dkim-helper \
|
||||||
|
30-db 40-postfix 50-dovecot \
|
||||||
|
60-rspamd-opendkim 61-opendmarc 62-clamav 63-fail2ban \
|
||||||
|
70-nginx 75-le-issue 80-app 90-services 95-woltguard 98-motd 99-summary
|
||||||
do
|
do
|
||||||
log ">>> Running ${STEP}.sh"
|
log ">>> Running ${STEP}.sh"
|
||||||
bash "./${STEP}.sh"
|
bash "./${STEP}.sh"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
##!/usr/bin/env bash
|
||||||
|
#set -euo pipefail
|
||||||
|
#
|
||||||
|
## --- Flags / Modi ---
|
||||||
|
#DEV_MODE=0
|
||||||
|
#PROXY_MODE=0
|
||||||
|
#NPM_IP=""
|
||||||
|
#
|
||||||
|
#while [[ $# -gt 0 ]]; do
|
||||||
|
# case "$1" in
|
||||||
|
# -dev) DEV_MODE=1 ;;
|
||||||
|
# -proxy) PROXY_MODE=1; NPM_IP="${2:-}"; shift ;;
|
||||||
|
# esac
|
||||||
|
# shift
|
||||||
|
#done
|
||||||
|
#
|
||||||
|
#APP_ENV="${APP_ENV:-$([[ $DEV_MODE -eq 1 ]] && echo local || echo production)}"
|
||||||
|
#APP_DEBUG="${APP_DEBUG:-$([[ $DEV_MODE -eq 1 ]] && echo true || echo false)}"
|
||||||
|
#export DEV_MODE PROXY_MODE NPM_IP APP_ENV APP_DEBUG
|
||||||
|
#
|
||||||
|
#DB_PASS="${DB_PASS:-$(openssl rand -hex 16)}"
|
||||||
|
#REDIS_PASS="${REDIS_PASS:-$(openssl rand -hex 16)}"
|
||||||
|
#
|
||||||
|
#export DB_PASS REDIS_PASS
|
||||||
|
#
|
||||||
|
#cd "$(dirname "$0")"
|
||||||
|
#source ./lib.sh
|
||||||
|
#require_root
|
||||||
|
#header
|
||||||
|
#
|
||||||
|
## ── Defaults ────────────────────────────────────────────────────────────────
|
||||||
|
#APP_NAME="${APP_NAME:-MailWolt}"
|
||||||
|
#APP_USER="${APP_USER:-mailwolt}"
|
||||||
|
#APP_GROUP="${APP_GROUP:-www-data}"
|
||||||
|
#APP_USER_PREFIX="${APP_USER_PREFIX:-mw}"
|
||||||
|
#APP_DIR="${APP_DIR:-/var/www/${APP_USER}}"
|
||||||
|
#
|
||||||
|
#BASE_DOMAIN="${BASE_DOMAIN:-example.com}"
|
||||||
|
#UI_SUB="${UI_SUB:-ui}"
|
||||||
|
#WEBMAIL_SUB="${WEBMAIL_SUB:-webmail}"
|
||||||
|
#MTA_SUB="${MTA_SUB:-mx}"
|
||||||
|
#
|
||||||
|
#DB_NAME="${DB_NAME:-${APP_USER}}"
|
||||||
|
#DB_USER="${DB_USER:-${APP_USER}}"
|
||||||
|
#
|
||||||
|
#SERVER_PUBLIC_IPV4="$(detect_ip)"
|
||||||
|
#SERVER_PUBLIC_IPV6="$(detect_ipv6)"
|
||||||
|
#DEFAULT_TZ="$(detect_timezone)"
|
||||||
|
#DEFAULT_LOCALE="$(guess_locale_from_tz "$DEFAULT_TZ")"
|
||||||
|
#
|
||||||
|
#echo -e "${GREY}Erkannte IP (v4): ${SERVER_PUBLIC_IPV4} v6: ${SERVER_PUBLIC_IPV6:-–}${NC}"
|
||||||
|
#
|
||||||
|
## ── Schöne, farbige Abfragen ────────────────────────────────────────────────
|
||||||
|
#echo -e "${CYAN}"
|
||||||
|
#echo "──────────────────────────────────────────────"
|
||||||
|
#echo -e " 📧 MailWolt Setup – Domain Konfiguration"
|
||||||
|
#echo "──────────────────────────────────────────────"
|
||||||
|
#echo -e "${NC}"
|
||||||
|
#
|
||||||
|
#MTA_DEFAULT="${MTA_SUB}.${BASE_DOMAIN}"
|
||||||
|
#UI_DEFAULT="${UI_SUB}.${BASE_DOMAIN}"
|
||||||
|
#WEBMAIL_DEFAULT="${WEBMAIL_SUB}.${BASE_DOMAIN}"
|
||||||
|
#
|
||||||
|
#ask_domain() {
|
||||||
|
# local __outvar="$1" label="$2" example="$3" defval="$4" input=""
|
||||||
|
# echo -e "${GREEN}[?]${NC} ${label}"
|
||||||
|
# echo -e " z.B. ${YELLOW}${example}${NC}"
|
||||||
|
# echo -e " Default: ${CYAN}${defval}${NC}"
|
||||||
|
# echo -ne " → Eingabe: ${CYAN}"
|
||||||
|
# read -r input
|
||||||
|
# echo -e "${NC}"
|
||||||
|
# if [[ -z "$input" ]]; then
|
||||||
|
# eval "$__outvar='$defval'"
|
||||||
|
# else
|
||||||
|
# eval "$__outvar='$input'"
|
||||||
|
# fi
|
||||||
|
#}
|
||||||
|
#
|
||||||
|
#ask_toggle() {
|
||||||
|
# local __outvar="$1" label="$2" defval="${3:-1}" input=""
|
||||||
|
# echo -ne "${GREEN}[?]${NC} ${label} (${CYAN}1${NC}=Ja / ${YELLOW}0${NC}=Nein) [Enter=${defval}]: "
|
||||||
|
# read -r input
|
||||||
|
# input="${input:-$defval}"
|
||||||
|
# case "$input" in
|
||||||
|
# 1|0) ;;
|
||||||
|
# *) echo -e "${YELLOW}Ungültig, nehme Default=${defval}.${NC}"; input="$defval" ;;
|
||||||
|
# esac
|
||||||
|
# eval "$__outvar='$input'"
|
||||||
|
#}
|
||||||
|
#
|
||||||
|
#ask_domain "MTA_FQDN" "Mailserver-FQDN (MX)" "mx.domain.tld" "$MTA_DEFAULT"
|
||||||
|
#ask_domain "UI_FQDN" "UI / Admin-Panel" "ui.domain.tld" "$UI_DEFAULT"
|
||||||
|
#ask_domain "WEBMAIL_FQDN" "Webmail-FQDN" "webmail.domain.tld" "$WEBMAIL_DEFAULT"
|
||||||
|
#
|
||||||
|
#echo -e "${CYAN}"
|
||||||
|
#echo "──────────────────────────────────────────────"
|
||||||
|
#echo -e " 🛡 Optionale Dienste"
|
||||||
|
#echo "──────────────────────────────────────────────"
|
||||||
|
#echo -e "${NC}"
|
||||||
|
#
|
||||||
|
#ask_toggle "CLAMAV_ENABLE" "ClamAV Virenscan aktivieren?" 1
|
||||||
|
#ask_toggle "OPENDMARC_ENABLE" "OpenDMARC auswerten?" 1
|
||||||
|
#ask_toggle "FAIL2BAN_ENABLE" "Fail2Ban aktivieren?" 1
|
||||||
|
#echo
|
||||||
|
#
|
||||||
|
## Defaults, wenn Enter gedrückt (Abwärtskompatibilität)
|
||||||
|
#MTA_FQDN="${MTA_FQDN:-${MTA_SUB}.${BASE_DOMAIN}}"
|
||||||
|
#UI_FQDN="${UI_FQDN:-${UI_SUB}.${BASE_DOMAIN}}"
|
||||||
|
#WEBMAIL_FQDN="${WEBMAIL_FQDN:-${WEBMAIL_SUB}.${BASE_DOMAIN}}"
|
||||||
|
#DKIM_ENABLE="${DKIM_ENABLE:-1}"
|
||||||
|
#DKIM_SELECTOR="${DKIM_SELECTOR:-mwl1}"
|
||||||
|
#DKIM_GENERATE="${DKIM_GENERATE:-1}"
|
||||||
|
#
|
||||||
|
## BASE_DOMAIN und Sub-Labels aus MTA/UI/WEBMAIL ableiten (robust)
|
||||||
|
#if [[ "$MTA_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
||||||
|
# MTA_SUB="${BASH_REMATCH[1]}"
|
||||||
|
# BASE_DOMAIN="${BASH_REMATCH[2]}"
|
||||||
|
#fi
|
||||||
|
#if [[ "$UI_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
||||||
|
# UI_SUB="${BASH_REMATCH[1]}"
|
||||||
|
#fi
|
||||||
|
#if [[ "$WEBMAIL_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
||||||
|
# WEBMAIL_SUB="${BASH_REMATCH[1]}"
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
#SYSMAIL_SUB="${SYSMAIL_SUB:-sysmail}"
|
||||||
|
#SYSMAIL_DOMAIN="${SYSMAIL_SUB}.${BASE_DOMAIN}"
|
||||||
|
## Kanonische Host-Variablen (NIE wieder zusammenbauen – nimm die FQDNs)
|
||||||
|
#MAIL_HOSTNAME="${MTA_FQDN}"
|
||||||
|
#UI_HOST="${UI_FQDN}"
|
||||||
|
#WEBMAIL_HOST="${WEBMAIL_FQDN}"
|
||||||
|
#
|
||||||
|
## Zeitzone/Locale sinnvoll setzen
|
||||||
|
#APP_TZ="${APP_TZ:-$DEFAULT_TZ}"
|
||||||
|
#APP_LOCALE="${APP_LOCALE:-$DEFAULT_LOCALE}"
|
||||||
|
#
|
||||||
|
## ── Variablen exportieren ───────────────────────────────────────────────────
|
||||||
|
#export APP_NAME APP_USER APP_GROUP APP_USER_PREFIX APP_DIR
|
||||||
|
#export BASE_DOMAIN UI_SUB WEBMAIL_SUB MTA_SUB
|
||||||
|
#export SYSMAIL_SUB SYSMAIL_DOMAIN DKIM_ENABLE DKIM_SELECTOR DKIM_GENERATE
|
||||||
|
#export UI_HOST WEBMAIL_HOST MAIL_HOSTNAME
|
||||||
|
#export DB_NAME DB_USER
|
||||||
|
#export SERVER_PUBLIC_IPV4 SERVER_PUBLIC_IPV6 APP_TZ APP_LOCALE
|
||||||
|
#export CLAMAV_ENABLE OPENDMARC_ENABLE FAIL2BAN_ENABLE
|
||||||
|
#
|
||||||
|
#install -d -m 0755 /etc/mailwolt
|
||||||
|
#cat >/etc/mailwolt/installer.env <<EOF
|
||||||
|
#BASE_DOMAIN=${BASE_DOMAIN}
|
||||||
|
#MTA_SUB=${MTA_SUB}
|
||||||
|
#UI_SUB=${UI_SUB}
|
||||||
|
#WEBMAIL_SUB=${WEBMAIL_SUB}
|
||||||
|
#
|
||||||
|
#MAIL_HOSTNAME=${MAIL_HOSTNAME}
|
||||||
|
#UI_HOST=${UI_HOST}
|
||||||
|
#WEBMAIL_HOST=${WEBMAIL_HOST}
|
||||||
|
#
|
||||||
|
#SYSMAIL_SUB=${SYSMAIL_SUB}
|
||||||
|
#SYSMAIL_DOMAIN=${SYSMAIL_DOMAIN}
|
||||||
|
#
|
||||||
|
#DKIM_ENABLE=${DKIM_ENABLE}
|
||||||
|
#DKIM_SELECTOR=${DKIM_SELECTOR}
|
||||||
|
#DKIM_GENERATE=${DKIM_GENERATE}
|
||||||
|
#
|
||||||
|
#DB_HOST=127.0.0.1
|
||||||
|
#DB_NAME=${DB_NAME}
|
||||||
|
#DB_USER=${DB_USER}
|
||||||
|
#DB_PASS=${DB_PASS}
|
||||||
|
#REDIS_PASS=${REDIS_PASS}
|
||||||
|
#
|
||||||
|
#SERVER_PUBLIC_IPV4=${SERVER_PUBLIC_IPV4}
|
||||||
|
#SERVER_PUBLIC_IPV6=${SERVER_PUBLIC_IPV6}
|
||||||
|
#APP_ENV=${APP_ENV}
|
||||||
|
#
|
||||||
|
#CLAMAV_ENABLE=${CLAMAV_ENABLE}
|
||||||
|
#OPENDMARC_ENABLE=${OPENDMARC_ENABLE}
|
||||||
|
#FAIL2BAN_ENABLE=${FAIL2BAN_ENABLE}
|
||||||
|
#EOF
|
||||||
|
#
|
||||||
|
#chmod 600 /etc/mailwolt/installer.env
|
||||||
|
#
|
||||||
|
## ── Sequenz ────────────────────────────────────────────────────────────────
|
||||||
|
#for STEP in 10-provision 20-ssl 21-le-deploy-hook 22-dkim-helper 30-db 40-postfix 50-dovecot 60-rspamd-opendkim 61-opendmarc 62-clamav 63-fail2ban 70-nginx 75-le-issue 80-app 90-services 95-woltguard 98-motd 99-summary
|
||||||
|
#do
|
||||||
|
# log ">>> Running ${STEP}.sh"
|
||||||
|
# bash "./${STEP}.sh"
|
||||||
|
#done
|
||||||
|
###!/usr/bin/env bash
|
||||||
|
##set -euo pipefail
|
||||||
|
##
|
||||||
|
### --- Flags / Modi ---
|
||||||
|
##DEV_MODE=0
|
||||||
|
##PROXY_MODE=0
|
||||||
|
##NPM_IP=""
|
||||||
|
##
|
||||||
|
##while [[ $# -gt 0 ]]; do
|
||||||
|
## case "$1" in
|
||||||
|
## -dev) DEV_MODE=1 ;;
|
||||||
|
## -proxy) PROXY_MODE=1; NPM_IP="${2:-}"; shift ;;
|
||||||
|
## esac
|
||||||
|
## shift
|
||||||
|
##done
|
||||||
|
##
|
||||||
|
##APP_ENV="${APP_ENV:-$([[ $DEV_MODE -eq 1 ]] && echo local || echo production)}"
|
||||||
|
##APP_DEBUG="${APP_DEBUG:-$([[ $DEV_MODE -eq 1 ]] && echo true || echo false)}"
|
||||||
|
##export DEV_MODE PROXY_MODE NPM_IP APP_ENV APP_DEBUG
|
||||||
|
##
|
||||||
|
##DB_PASS="${DB_PASS:-$(openssl rand -hex 16)}"
|
||||||
|
##REDIS_PASS="${REDIS_PASS:-$(openssl rand -hex 16)}"
|
||||||
|
##
|
||||||
|
##export DB_PASS REDIS_PASS
|
||||||
|
##
|
||||||
|
##cd "$(dirname "$0")"
|
||||||
|
##source ./lib.sh
|
||||||
|
##require_root
|
||||||
|
##header
|
||||||
|
##
|
||||||
|
### ── Defaults ────────────────────────────────────────────────────────────────
|
||||||
|
##APP_NAME="${APP_NAME:-MailWolt}"
|
||||||
|
##APP_USER="${APP_USER:-mailwolt}"
|
||||||
|
##APP_GROUP="${APP_GROUP:-www-data}"
|
||||||
|
##APP_USER_PREFIX="${APP_USER_PREFIX:-mw}"
|
||||||
|
##APP_DIR="${APP_DIR:-/var/www/${APP_USER}}"
|
||||||
|
##
|
||||||
|
##BASE_DOMAIN="${BASE_DOMAIN:-example.com}"
|
||||||
|
##UI_SUB="${UI_SUB:-ui}"
|
||||||
|
##WEBMAIL_SUB="${WEBMAIL_SUB:-webmail}"
|
||||||
|
##MTA_SUB="${MTA_SUB:-mx}"
|
||||||
|
##
|
||||||
|
##DB_NAME="${DB_NAME:-${APP_USER}}"
|
||||||
|
##DB_USER="${DB_USER:-${APP_USER}}"
|
||||||
|
##
|
||||||
|
##SERVER_PUBLIC_IPV4="$(detect_ip)"
|
||||||
|
##SERVER_PUBLIC_IPV6="$(detect_ipv6)"
|
||||||
|
##DEFAULT_TZ="$(detect_timezone)"
|
||||||
|
##DEFAULT_LOCALE="$(guess_locale_from_tz "$DEFAULT_TZ")"
|
||||||
|
##
|
||||||
|
##echo -e "${GREY}Erkannte IP (v4): ${SERVER_PUBLIC_IPV4} v6: ${SERVER_PUBLIC_IPV6:-–}${NC}"
|
||||||
|
##
|
||||||
|
### ── FQDNs abfragen ───────────────────────────────────────────────────────────
|
||||||
|
##read -r -p "Mailserver FQDN (MX, z.B. mx.domain.tld) [Enter=${MTA_SUB}.${BASE_DOMAIN}]: " MTA_FQDN
|
||||||
|
##read -r -p "UI / Admin-Panel FQDN (z.B. ui.domain.tld) [Enter=${UI_SUB}.${BASE_DOMAIN}]: " UI_FQDN
|
||||||
|
##read -r -p "Webmail FQDN (z.B. webmail.domain.tld) [Enter=${WEBMAIL_SUB}.${BASE_DOMAIN}]: " WEBMAIL_FQDN
|
||||||
|
##
|
||||||
|
### Defaults, wenn Enter gedrückt
|
||||||
|
##MTA_FQDN="${MTA_FQDN:-${MTA_SUB}.${BASE_DOMAIN}}"
|
||||||
|
##UI_FQDN="${UI_FQDN:-${UI_SUB}.${BASE_DOMAIN}}"
|
||||||
|
##WEBMAIL_FQDN="${WEBMAIL_FQDN:-${WEBMAIL_SUB}.${BASE_DOMAIN}}"
|
||||||
|
##DKIM_ENABLE="${DKIM_ENABLE:-1}"
|
||||||
|
##DKIM_SELECTOR="${DKIM_SELECTOR:-mwl1}"
|
||||||
|
##DKIM_GENERATE="${DKIM_GENERATE:-1}"
|
||||||
|
##
|
||||||
|
### BASE_DOMAIN und Sub-Labels aus MTA/UI/WEBMAIL ableiten (robust)
|
||||||
|
##if [[ "$MTA_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
||||||
|
## MTA_SUB="${BASH_REMATCH[1]}"
|
||||||
|
## BASE_DOMAIN="${BASH_REMATCH[2]}"
|
||||||
|
##fi
|
||||||
|
##if [[ "$UI_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
||||||
|
## UI_SUB="${BASH_REMATCH[1]}"
|
||||||
|
##fi
|
||||||
|
##if [[ "$WEBMAIL_FQDN" =~ ^([^.]+)\.(.+)$ ]]; then
|
||||||
|
## WEBMAIL_SUB="${BASH_REMATCH[1]}"
|
||||||
|
##fi
|
||||||
|
##
|
||||||
|
##SYSMAIL_SUB="${SYSMAIL_SUB:-sysmail}"
|
||||||
|
##SYSMAIL_DOMAIN="${SYSMAIL_SUB}.${BASE_DOMAIN}"
|
||||||
|
### Kanonische Host-Variablen (NIE wieder zusammenbauen – nimm die FQDNs)
|
||||||
|
##MAIL_HOSTNAME="${MTA_FQDN}"
|
||||||
|
##UI_HOST="${UI_FQDN}"
|
||||||
|
##WEBMAIL_HOST="${WEBMAIL_FQDN}"
|
||||||
|
##
|
||||||
|
### Zeitzone/Locale sinnvoll setzen (könntest du auch noch abfragen)
|
||||||
|
##APP_TZ="${APP_TZ:-$DEFAULT_TZ}"
|
||||||
|
##APP_LOCALE="${APP_LOCALE:-$DEFAULT_LOCALE}"
|
||||||
|
##
|
||||||
|
### ── Variablen exportieren ───────────────────────────────────────────────────
|
||||||
|
##export APP_NAME APP_USER APP_GROUP APP_USER_PREFIX APP_DIR
|
||||||
|
##export BASE_DOMAIN UI_SUB WEBMAIL_SUB MTA_SUB
|
||||||
|
##export SYSMAIL_SUB SYSMAIL_DOMAIN DKIM_ENABLE DKIM_SELECTOR DKIM_GENERATE
|
||||||
|
##export UI_HOST WEBMAIL_HOST MAIL_HOSTNAME
|
||||||
|
##export DB_NAME DB_USER
|
||||||
|
##export SERVER_PUBLIC_IPV4 SERVER_PUBLIC_IPV6 APP_TZ APP_LOCALE
|
||||||
|
##
|
||||||
|
##install -d -m 0755 /etc/mailwolt
|
||||||
|
##cat >/etc/mailwolt/installer.env <<EOF
|
||||||
|
##BASE_DOMAIN=${BASE_DOMAIN}
|
||||||
|
##MTA_SUB=${MTA_SUB}
|
||||||
|
##UI_SUB=${UI_SUB}
|
||||||
|
##WEBMAIL_SUB=${WEBMAIL_SUB}
|
||||||
|
##
|
||||||
|
##MAIL_HOSTNAME=${MAIL_HOSTNAME}
|
||||||
|
##UI_HOST=${UI_HOST}
|
||||||
|
##WEBMAIL_HOST=${WEBMAIL_HOST}
|
||||||
|
##
|
||||||
|
##SYSMAIL_SUB=${SYSMAIL_SUB}
|
||||||
|
##SYSMAIL_DOMAIN=${SYSMAIL_DOMAIN}
|
||||||
|
##
|
||||||
|
##DKIM_ENABLE=${DKIM_ENABLE}
|
||||||
|
##DKIM_SELECTOR=${DKIM_SELECTOR}
|
||||||
|
##DKIM_GENERATE=${DKIM_GENERATE}
|
||||||
|
##
|
||||||
|
##DB_HOST=127.0.0.1
|
||||||
|
##DB_NAME=${DB_NAME}
|
||||||
|
##DB_USER=${DB_USER}
|
||||||
|
##DB_PASS=${DB_PASS}
|
||||||
|
##REDIS_PASS=${REDIS_PASS}
|
||||||
|
##
|
||||||
|
##SERVER_PUBLIC_IPV4=${SERVER_PUBLIC_IPV4}
|
||||||
|
##SERVER_PUBLIC_IPV6=${SERVER_PUBLIC_IPV6}
|
||||||
|
##APP_ENV=${APP_ENV}
|
||||||
|
##
|
||||||
|
##CLAMAV_ENABLE=1
|
||||||
|
##OPENDMARC_ENABLE=1
|
||||||
|
##FAIL2BAN_ENABLE=1
|
||||||
|
##EOF
|
||||||
|
##
|
||||||
|
##chmod 600 /etc/mailwolt/installer.env
|
||||||
|
##
|
||||||
|
### ── Sequenz ────────────────────────────────────────────────────────────────
|
||||||
|
##for STEP in 10-provision 20-ssl 21-le-deploy-hook 22-dkim-helper 30-db 40-postfix 50-dovecot 60-rspamd-opendkim 61-opendmarc 62-clamav 63-fail2ban 70-nginx 75-le-issue 80-app 90-services 95-woltguard 98-motd 99-summary
|
||||||
|
##do
|
||||||
|
## log ">>> Running ${STEP}.sh"
|
||||||
|
## bash "./${STEP}.sh"
|
||||||
|
##done
|
||||||
|
|
@ -0,0 +1,300 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# -------- Konfiguration --------
|
||||||
|
APP_USER="mailwolt"
|
||||||
|
APP_DIR="/var/www/mailwolt"
|
||||||
|
BRANCH="${BRANCH:-main}" # nur relevant bei UPDATE_MODE=branch
|
||||||
|
MODE="${UPDATE_MODE:-tags}" # tags | branch
|
||||||
|
|
||||||
|
# -------- 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
|
||||||
|
systemctl restart "$u"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# -------- 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; }
|
||||||
|
|
||||||
|
echo "[i] Prüfe Repository …"
|
||||||
|
OLD_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
|
||||||
|
NEW_REV="$OLD_REV"
|
||||||
|
|
||||||
|
if [[ "$MODE" = "tags" ]]; then
|
||||||
|
# Auf neuesten Release-Tag wechseln (semantisch sortiert)
|
||||||
|
LATEST_TAG="$(as_app "cd ${APP_DIR} && git fetch --tags --quiet origin && git tag --list | sort -V | tail -n1")"
|
||||||
|
if [[ -z "$LATEST_TAG" ]]; then
|
||||||
|
echo "[!] Keine Tags gefunden – falle auf origin/${BRANCH} zurück"
|
||||||
|
as_app "cd ${APP_DIR} && git fetch --quiet origin ${BRANCH} && git checkout -q ${BRANCH} && git pull --ff-only origin ${BRANCH}"
|
||||||
|
else
|
||||||
|
TARGET_REV="$(as_app "cd ${APP_DIR} && git rev-list -n1 ${LATEST_TAG}")"
|
||||||
|
if [[ "$TARGET_REV" = "$OLD_REV" ]]; then
|
||||||
|
echo "[✓] Bereits auf neuestem Release (${LATEST_TAG}) – nichts zu tun."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "[i] Checkout auf Release ${LATEST_TAG} (${TARGET_REV:0:7}) …"
|
||||||
|
as_app "cd ${APP_DIR} && git checkout -q ${LATEST_TAG}"
|
||||||
|
fi
|
||||||
|
NEW_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
|
||||||
|
else
|
||||||
|
# Rolling: branch folgen
|
||||||
|
as_app "cd ${APP_DIR} && git fetch --quiet origin ${BRANCH}"
|
||||||
|
BEHIND="$(as_app "cd ${APP_DIR} && git rev-list --count HEAD..origin/${BRANCH} || echo 0")"
|
||||||
|
if [[ "$BEHIND" -eq 0 ]]; then
|
||||||
|
echo "[✓] Branch origin/${BRANCH} ist bereits aktuell – nichts zu tun."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "[i] Es gibt ${BEHIND} neue Commit(s) – ziehe Änderungen …"
|
||||||
|
as_app "cd ${APP_DIR} && git checkout -q ${BRANCH} && git pull --ff-only origin ${BRANCH}"
|
||||||
|
NEW_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -------- Änderungstypen ermitteln --------
|
||||||
|
CHANGED_FILES="$(as_app "cd ${APP_DIR} && git diff --name-only ${OLD_REV}..${NEW_REV}")"
|
||||||
|
|
||||||
|
NEED_COMPOSER=0
|
||||||
|
NEED_MIGRATIONS=0
|
||||||
|
NEED_FRONTEND=0
|
||||||
|
NEED_PHP_RESTART=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|resources/|public/.*\.(js|css))' && NEED_FRONTEND=1
|
||||||
|
echo "$CHANGED_FILES" | grep -qE '^(app/|routes/|config/|resources/views/)' && NEED_PHP_RESTART=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)"
|
||||||
|
|
||||||
|
# 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."
|
||||||
|
# Build-Info trotzdem aktualisieren
|
||||||
|
INST_VER="$(as_app "cd ${APP_DIR} && (cat VERSION 2>/dev/null || echo dev)")"
|
||||||
|
printf "version=%s\nrev=%s\nupdated=%s\n" "$INST_VER" "$NEW_REV" "$(date -Is)" > /etc/mailwolt/build.info || true
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -------- Gezielter Build/Deploy --------
|
||||||
|
if [[ $NEED_COMPOSER -eq 1 ]]; then
|
||||||
|
echo "[i] Composer …"
|
||||||
|
as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader"
|
||||||
|
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
|
||||||
|
echo "[i] Cache/Optimierungen …"
|
||||||
|
as_app "cd ${APP_DIR} && php artisan config:cache && php artisan route:cache || true"
|
||||||
|
as_app "cd ${APP_DIR} && php artisan queue:restart || true"
|
||||||
|
as_app "cd ${APP_DIR} && php artisan optimize:clear || true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $NEED_FRONTEND -eq 1 ]]; then
|
||||||
|
echo "[i] Frontend build …"
|
||||||
|
as_app "cd ${APP_DIR} && (npm ci --no-audit --no-fund || npm install)"
|
||||||
|
as_app "cd ${APP_DIR} && npm run build"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -------- Dienste nur wenn nötig --------
|
||||||
|
echo "[i] Dienste neu laden/neustarten (gezielt) …"
|
||||||
|
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
|
||||||
|
|
||||||
|
# -------- Build-Info ablegen --------
|
||||||
|
INST_VER="$(as_app "cd ${APP_DIR} && (cat VERSION 2>/dev/null || echo dev)")"
|
||||||
|
printf "version=%s\nrev=%s\nupdated=%s\n" "$INST_VER" "$NEW_REV" "$(date -Is)" > /etc/mailwolt/build.info || true
|
||||||
|
|
||||||
|
echo "[✓] Update abgeschlossen: ${OLD_REV:0:7} → ${NEW_REV:0:7} (Version: ${INST_VER})"
|
||||||
|
|
||||||
|
##!/usr/bin/env bash
|
||||||
|
#set -euo pipefail
|
||||||
|
#
|
||||||
|
#APP_USER="mailwolt"
|
||||||
|
#APP_DIR="/var/www/mailwolt"
|
||||||
|
#BRANCH="${BRANCH:-main}" # bei Bedarf anpassen
|
||||||
|
#
|
||||||
|
#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
|
||||||
|
# systemctl list-unit-files | grep -q "^${u}\.service" && { systemctl restart "$u"; return 0; }
|
||||||
|
# done
|
||||||
|
# return 0
|
||||||
|
#}
|
||||||
|
#
|
||||||
|
#[[ "$(id -u)" -eq 0 ]] || { echo "[!] Bitte als root ausführen"; exit 1; }
|
||||||
|
#
|
||||||
|
##!/usr/bin/env bash
|
||||||
|
#set -euo pipefail
|
||||||
|
#APP_USER="mailwolt"
|
||||||
|
#APP_DIR="/var/www/mailwolt"
|
||||||
|
#MODE="${UPDATE_MODE:-tags}"
|
||||||
|
#
|
||||||
|
#as_app(){ sudo -u "$APP_USER" -H bash -lc "$*"; }
|
||||||
|
#
|
||||||
|
## --- Ab hier wie gehabt ---
|
||||||
|
#echo "[i] Prüfe Repository …"
|
||||||
|
#if [[ "$MODE" = "tags" ]]; then
|
||||||
|
# LATEST_TAG="$(as_app "cd ${APP_DIR} && git fetch --tags --quiet origin && git tag --list | sort -V | tail -n1")"
|
||||||
|
# if [[ -n "$LATEST_TAG" ]]; then
|
||||||
|
# OLD_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
|
||||||
|
# echo "[i] Checkout auf neuesten Release: ${LATEST_TAG}"
|
||||||
|
# as_app "cd ${APP_DIR} && git checkout -q ${LATEST_TAG}"
|
||||||
|
# NEW_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
|
||||||
|
# else
|
||||||
|
# echo "[!] Keine Tags gefunden, falle auf origin/main zurück"
|
||||||
|
# as_app "cd ${APP_DIR} && git pull --ff-only origin main"
|
||||||
|
# fi
|
||||||
|
#else
|
||||||
|
# as_app "cd ${APP_DIR} && git fetch --quiet origin main && git pull --ff-only origin main"
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
#echo "[i] Prüfe Repository …"
|
||||||
|
#OLD_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
|
||||||
|
#as_app "cd ${APP_DIR} && git fetch --tags --quiet origin ${BRANCH}"
|
||||||
|
#BEHIND="$(as_app "cd ${APP_DIR} && git rev-list --count HEAD..origin/${BRANCH} || echo 0")"
|
||||||
|
#
|
||||||
|
#if [[ "${BEHIND}" -eq 0 ]]; then
|
||||||
|
# echo "[✓] Bereits aktuell – nichts zu tun."
|
||||||
|
# exit 0
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
#echo "[i] Es gibt ${BEHIND} neue Commit(s) – ziehe Änderungen …"
|
||||||
|
#as_app "cd ${APP_DIR} && git pull --ff-only origin ${BRANCH}"
|
||||||
|
#NEW_REV="$(as_app "cd ${APP_DIR} && git rev-parse HEAD")"
|
||||||
|
#
|
||||||
|
## Welche Bereiche haben sich geändert?
|
||||||
|
#CHANGED_FILES="$(as_app "cd ${APP_DIR} && git diff --name-only ${OLD_REV}..${NEW_REV}")"
|
||||||
|
#
|
||||||
|
#NEED_COMPOSER=0
|
||||||
|
#NEED_MIGRATIONS=0
|
||||||
|
#NEED_FRONTEND=0
|
||||||
|
#NEED_PHP_RESTART=0
|
||||||
|
#
|
||||||
|
#if echo "$CHANGED_FILES" | grep -qE '^(composer\.json|composer\.lock)'; then
|
||||||
|
# NEED_COMPOSER=1
|
||||||
|
#fi
|
||||||
|
#if echo "$CHANGED_FILES" | grep -qE '^database/migrations/'; then
|
||||||
|
# NEED_MIGRATIONS=1
|
||||||
|
#fi
|
||||||
|
#if echo "$CHANGED_FILES" | grep -qE '^(package(-lock)?\.json|vite\.config\.|resources/|public/.*\.(js|css))'; then
|
||||||
|
# NEED_FRONTEND=1
|
||||||
|
#fi
|
||||||
|
## PHP-Code/Views/Config geändert?
|
||||||
|
#if echo "$CHANGED_FILES" | grep -qE '^(app/|routes/|config/|resources/views/)'; then
|
||||||
|
# NEED_PHP_RESTART=1
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
#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 "[i] Führe Build/Deploy (gezielt) aus …"
|
||||||
|
#if [[ $NEED_COMPOSER -eq 1 ]]; then
|
||||||
|
# as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader"
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
#if [[ $NEED_MIGRATIONS -eq 1 ]]; then
|
||||||
|
# as_app "cd ${APP_DIR} && php artisan migrate --force"
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
## Cache & Queue nur wenn relevant
|
||||||
|
#if [[ $NEED_PHP_RESTART -eq 1 || $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 ]]; then
|
||||||
|
# as_app "cd ${APP_DIR} && php artisan config:cache && php artisan route:cache || true"
|
||||||
|
# as_app "cd ${APP_DIR} && php artisan queue:restart || true"
|
||||||
|
# as_app "cd ${APP_DIR} && php artisan optimize:clear || true"
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
#if [[ $NEED_FRONTEND -eq 1 ]]; then
|
||||||
|
# as_app "cd ${APP_DIR} && (npm ci --no-audit --no-fund || npm install)"
|
||||||
|
# as_app "cd ${APP_DIR} && npm run build"
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
## Dienste nur neu laden/starten wenn nötig
|
||||||
|
#ANY_RUNTIME_CHANGE=0
|
||||||
|
#[[ $NEED_COMPOSER -eq 1 || $NEED_MIGRATIONS -eq 1 || $NEED_FRONTEND -eq 1 || $NEED_PHP_RESTART -eq 1 ]] && ANY_RUNTIME_CHANGE=1
|
||||||
|
#
|
||||||
|
#if [[ $ANY_RUNTIME_CHANGE -eq 1 ]]; then
|
||||||
|
# echo "[i] Dienste neu laden/neustarten (gezielt) …"
|
||||||
|
# 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
|
||||||
|
# # Webserver nur bei Assets/Views/Config
|
||||||
|
# if [[ $NEED_FRONTEND -eq 1 || $NEED_PHP_RESTART -eq 1 ]]; then
|
||||||
|
# reload_if_active nginx
|
||||||
|
# fi
|
||||||
|
#else
|
||||||
|
# echo "[i] Nichts zum Updaten."
|
||||||
|
#fi
|
||||||
|
#
|
||||||
|
#echo "[✓] Update auf ${NEW_REV:0:7} abgeschlossen."
|
||||||
|
|
||||||
|
##!/usr/bin/env bash
|
||||||
|
#set -euo pipefail
|
||||||
|
#
|
||||||
|
#APP_USER="mailwolt"
|
||||||
|
#APP_DIR="/var/www/mailwolt"
|
||||||
|
#
|
||||||
|
#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
|
||||||
|
# systemctl list-unit-files | grep -q "^${u}\.service" && { systemctl restart "$u"; return 0; }
|
||||||
|
# done
|
||||||
|
# return 0
|
||||||
|
#}
|
||||||
|
#
|
||||||
|
#[[ "$(id -u)" -eq 0 ]] || { echo "[!] Bitte als root ausführen"; exit 1; }
|
||||||
|
#
|
||||||
|
#echo "[i] Code-Update & Build als ${APP_USER} …"
|
||||||
|
#as_app "cd ${APP_DIR} && git pull --ff-only"
|
||||||
|
#as_app "cd ${APP_DIR} && composer install --no-interaction --prefer-dist --optimize-autoloader"
|
||||||
|
#as_app "cd ${APP_DIR} && php artisan migrate --force"
|
||||||
|
#as_app "cd ${APP_DIR} && php artisan config:cache && php artisan route:cache || true && php artisan queue:restart || true && php artisan optimize:clear"
|
||||||
|
#as_app "cd ${APP_DIR} && (npm ci --no-audit --no-fund || npm install)"
|
||||||
|
#as_app "cd ${APP_DIR} && npm run build"
|
||||||
|
#
|
||||||
|
#echo "[i] Dienste neu laden/neustarten …"
|
||||||
|
#restart_php_fpm
|
||||||
|
#restart_if_exists "${APP_USER}-queue"
|
||||||
|
#restart_if_exists "${APP_USER}-schedule"
|
||||||
|
#restart_if_exists "${APP_USER}-ws"
|
||||||
|
#reload_if_active nginx
|
||||||
|
#reload_if_active opendkim
|
||||||
|
#reload_if_active postfix
|
||||||
|
#reload_if_active dovecot
|
||||||
|
#reload_if_active rspamd
|
||||||
|
#
|
||||||
|
#echo "[✓] Update abgeschlossen."
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MSG=""
|
||||||
|
BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo main)"
|
||||||
|
REMOTE="${REMOTE:-origin}"
|
||||||
|
|
||||||
|
usage(){ echo "Usage: $0 -m \"commit message\" [-b branch]"; exit 1; }
|
||||||
|
|
||||||
|
while getopts ":m:b:" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
m) MSG="$OPTARG" ;;
|
||||||
|
b) BRANCH="$OPTARG" ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
|
[[ -n "$MSG" ]] || usage
|
||||||
|
git rev-parse --git-dir >/dev/null 2>&1 || { echo "[x] kein Git-Repo"; exit 1; }
|
||||||
|
|
||||||
|
echo "[i] Add/Commit → $BRANCH"
|
||||||
|
git add -A
|
||||||
|
# Kein Commit, wenn nichts geändert ist
|
||||||
|
if ! git diff --cached --quiet; then
|
||||||
|
git commit -m "$MSG"
|
||||||
|
else
|
||||||
|
echo "[i] Nichts zu committen (Index leer) – pushe nur."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[i] Push → $REMOTE/$BRANCH"
|
||||||
|
git push "$REMOTE" "$BRANCH"
|
||||||
|
echo "[✓] Done."
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REMOTE="${REMOTE:-origin}"
|
||||||
|
BRANCH="${BRANCH:-main}"
|
||||||
|
ALLOW_DIRTY=0
|
||||||
|
VERSION=""
|
||||||
|
MSG=""
|
||||||
|
|
||||||
|
usage(){
|
||||||
|
echo "Usage: $0 <X.Y.Z> [-m \"release notes\"] [-b branch] [--allow-dirty]"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Args
|
||||||
|
[[ $# -ge 1 ]] || usage
|
||||||
|
VERSION="$1"; shift || true
|
||||||
|
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "[x] Ungültige Version: $VERSION (erwarte SemVer X.Y.Z)"; exit 1; }
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-m) MSG="$2"; shift 2 ;;
|
||||||
|
-b) BRANCH="$2"; shift 2 ;;
|
||||||
|
--allow-dirty) ALLOW_DIRTY=1; shift ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
git rev-parse --git-dir >/dev/null 2>&1 || { echo "[x] kein Git-Repo"; exit 1; }
|
||||||
|
|
||||||
|
# Clean tree?
|
||||||
|
if [[ $ALLOW_DIRTY -eq 0 ]]; then
|
||||||
|
if ! git diff --quiet || ! git diff --cached --quiet; then
|
||||||
|
echo "[x] Arbeitsbaum nicht sauber. Committe oder nutze --allow-dirty."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Aktuellen Stand holen
|
||||||
|
git fetch --quiet "$REMOTE" --tags
|
||||||
|
# Branch check-out/sync
|
||||||
|
git checkout -q "$BRANCH"
|
||||||
|
git pull --ff-only "$REMOTE" "$BRANCH"
|
||||||
|
|
||||||
|
TAG="v${VERSION}"
|
||||||
|
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
|
||||||
|
echo "[x] Tag ${TAG} existiert bereits."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
LAST_TAG="$(git describe --tags --abbrev=0 2>/dev/null || true)"
|
||||||
|
if [[ -n "$LAST_TAG" ]]; then
|
||||||
|
CHANGELOG="$(git log --pretty=format:'- %s (%h)' "${LAST_TAG}..HEAD" || true)"
|
||||||
|
else
|
||||||
|
CHANGELOG="$(git log --pretty=format:'- %s (%h)' || true)"
|
||||||
|
fi
|
||||||
|
[[ -n "$CHANGELOG" ]] || CHANGELOG="- initial release content"
|
||||||
|
|
||||||
|
# VERSION bumpen
|
||||||
|
echo -n "$VERSION" > VERSION
|
||||||
|
git add VERSION
|
||||||
|
git commit -m "chore(release): v${VERSION}"
|
||||||
|
|
||||||
|
# Tag-Message bauen
|
||||||
|
if [[ -z "$MSG" ]]; then
|
||||||
|
read -r -d '' MSG <<EOF || true
|
||||||
|
MailWolt v${VERSION}
|
||||||
|
|
||||||
|
Changes since ${LAST_TAG:-repo start}:
|
||||||
|
${CHANGELOG}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
git tag -a "$TAG" -m "$MSG"
|
||||||
|
|
||||||
|
# Push commit + tag
|
||||||
|
git push "$REMOTE" "$BRANCH"
|
||||||
|
git push "$REMOTE" "$TAG"
|
||||||
|
|
||||||
|
echo "[✓] Release ${TAG} erstellt & gepusht."
|
||||||
Loading…
Reference in New Issue