Init Mailwolt installer
commit
8cad8eceb8
|
|
@ -0,0 +1,17 @@
|
|||
# ===================== HTTP (Port 80) =====================
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name _;
|
||||
|
||||
# ACME HTTP-01
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root /var/www/letsencrypt;
|
||||
allow all;
|
||||
}
|
||||
|
||||
## __HTTP_BODY__
|
||||
}
|
||||
|
||||
# ===================== HTTPS (Port 443) ====================
|
||||
## __SSL_SERVER_BLOCK__
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
log "Pakete installieren …"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -y
|
||||
# Minimal aber vollständig
|
||||
apt-get -y -o Dpkg::Options::="--force-confdef" \
|
||||
-o Dpkg::Options::="--force-confold" install \
|
||||
postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql \
|
||||
mariadb-server mariadb-client redis-server \
|
||||
rspamd opendkim opendkim-tools \
|
||||
nginx php php-fpm php-cli php-mbstring php-xml php-curl php-zip php-mysql php-redis php-gd \
|
||||
unzip curl composer git certbot python3-certbot-nginx \
|
||||
ca-certificates rsyslog sudo openssl monit acl netcat-openbsd
|
||||
|
||||
log "Systemuser/Dirs …"
|
||||
id vmail >/dev/null 2>&1 || adduser --system --group --home /var/mail vmail
|
||||
id "$APP_USER" >/dev/null 2>&1 || adduser --disabled-password --gecos "" "$APP_USER"
|
||||
usermod -a -G "$APP_GROUP" "$APP_USER" || true
|
||||
install -d -m 0755 -o root -g root /var/www
|
||||
install -d -m 0775 -o "$APP_USER" -g "$APP_GROUP" "$APP_DIR"
|
||||
|
||||
log "MariaDB include-fix …"
|
||||
mkdir -p /etc/mysql/mariadb.conf.d
|
||||
[[ -f /etc/mysql/mariadb.cnf ]] || echo '!include /etc/mysql/mariadb.conf.d/*.cnf' > /etc/mysql/mariadb.cnf
|
||||
|
||||
log "Redis absichern …"
|
||||
REDIS_CONF="/etc/redis/redis.conf"
|
||||
REDIS_PASS="${REDIS_PASS:-$(openssl rand -hex 16)}"
|
||||
sed -i 's/^\s*#\?\s*bind .*/bind 127.0.0.1/' "$REDIS_CONF"
|
||||
sed -i 's/^\s*#\?\s*protected-mode .*/protected-mode yes/' "$REDIS_CONF"
|
||||
grep -qE '^\s*#?\s*requirepass ' "$REDIS_CONF" \
|
||||
&& sed -i "s/^\s*#\?\s*requirepass .*/requirepass ${REDIS_PASS}/" "$REDIS_CONF" \
|
||||
|| printf "\nrequirepass %s\n" "${REDIS_PASS}" >> "$REDIS_CONF"
|
||||
systemctl enable --now redis-server
|
||||
systemctl restart redis-server || true
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
CONF_BASE="/etc/${APP_USER}"
|
||||
CERT_DIR="${CONF_BASE}/ssl"
|
||||
UI_SSL_DIR="/etc/ssl/ui"; WEBMAIL_SSL_DIR="/etc/ssl/webmail"; MAIL_SSL_DIR="/etc/ssl/mail"
|
||||
UI_CERT="${UI_SSL_DIR}/fullchain.pem"; UI_KEY="${UI_SSL_DIR}/privkey.pem"
|
||||
WEBMAIL_CERT="${WEBMAIL_SSL_DIR}/fullchain.pem"; WEBMAIL_KEY="${WEBMAIL_SSL_DIR}/privkey.pem"
|
||||
MAIL_CERT="${MAIL_SSL_DIR}/fullchain.pem"; MAIL_KEY="${MAIL_SSL_DIR}/privkey.pem"
|
||||
|
||||
install -d -m 0750 "$CERT_DIR"
|
||||
CERT="${CERT_DIR}/cert.pem"; KEY="${CERT_DIR}/key.pem"
|
||||
|
||||
if [[ ! -s "$CERT" || ! -s "$KEY" ]]; then
|
||||
log "Self-signed Zertifikat erzeugen …"
|
||||
OSSL_CFG="${CERT_DIR}/openssl.cnf"
|
||||
cat > "$OSSL_CFG" <<CFG
|
||||
[req]
|
||||
default_bits=2048
|
||||
prompt=no
|
||||
default_md=sha256
|
||||
req_extensions=req_ext
|
||||
distinguished_name=dn
|
||||
[dn]
|
||||
CN=${SERVER_PUBLIC_IPV4}
|
||||
O=${APP_NAME}
|
||||
C=DE
|
||||
[req_ext]
|
||||
subjectAltName=@alt_names
|
||||
[alt_names]
|
||||
IP.1=${SERVER_PUBLIC_IPV4}
|
||||
CFG
|
||||
openssl req -x509 -newkey rsa:2048 -days 825 -nodes -keyout "$KEY" -out "$CERT" -config "$OSSL_CFG"
|
||||
chgrp www-data "$CERT" "$KEY" || true
|
||||
chmod 640 "$KEY" "$CERT"
|
||||
fi
|
||||
|
||||
install -d -m 0755 "$UI_SSL_DIR" "$WEBMAIL_SSL_DIR" "$MAIL_SSL_DIR"
|
||||
ln -sf "$CERT" "$UI_CERT"; ln -sf "$KEY" "$UI_KEY"
|
||||
ln -sf "$CERT" "$WEBMAIL_CERT";ln -sf "$KEY" "$WEBMAIL_KEY"
|
||||
ln -sf "$CERT" "$MAIL_CERT"; ln -sf "$KEY" "$MAIL_KEY"
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
log "MariaDB vorbereiten …"
|
||||
systemctl enable --now mariadb
|
||||
mysql -uroot <<SQL
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
|
||||
CREATE USER IF NOT EXISTS '${DB_USER}'@'127.0.0.1' IDENTIFIED BY '${DB_PASS}';
|
||||
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';
|
||||
GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'127.0.0.1';
|
||||
FLUSH PRIVILEGES;
|
||||
SQL
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#!/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 "Postfix konfigurieren …"
|
||||
postconf -e "myhostname = ${MAIL_HOSTNAME}"
|
||||
postconf -e "myorigin = \$myhostname"
|
||||
postconf -e "mydestination = "
|
||||
postconf -e "inet_interfaces = all"
|
||||
postconf -e "inet_protocols = ipv4"
|
||||
postconf -e "smtpd_banner = \$myhostname ESMTP"
|
||||
|
||||
postconf -e "smtpd_tls_cert_file=${MAIL_CERT}"
|
||||
postconf -e "smtpd_tls_key_file=${MAIL_KEY}"
|
||||
postconf -e "smtpd_tls_security_level = may"
|
||||
postconf -e "smtp_tls_security_level = may"
|
||||
postconf -e "smtpd_tls_received_header = yes"
|
||||
postconf -e "smtpd_tls_protocols=!SSLv2,!SSLv3"
|
||||
postconf -e "smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3"
|
||||
postconf -e "smtpd_tls_loglevel=1"
|
||||
postconf -e "smtp_tls_loglevel=1"
|
||||
|
||||
postconf -e "disable_vrfy_command = yes"
|
||||
postconf -e "smtpd_helo_required = yes"
|
||||
|
||||
postconf -e "milter_default_action = accept"
|
||||
postconf -e "milter_protocol = 6"
|
||||
postconf -e "smtpd_milters = inet:127.0.0.1:11332, inet:127.0.0.1:8891"
|
||||
postconf -e "non_smtpd_milters = inet:127.0.0.1:11332, inet:127.0.0.1:8891"
|
||||
|
||||
postconf -e "smtpd_sasl_type = dovecot"
|
||||
postconf -e "smtpd_sasl_path = private/auth"
|
||||
postconf -e "smtpd_sasl_auth_enable = yes"
|
||||
postconf -e "smtpd_sasl_security_options = noanonymous"
|
||||
|
||||
postconf -e "smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination"
|
||||
postconf -e "smtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination"
|
||||
|
||||
postconf -M "smtp/inet=smtp inet n - n - - smtpd -o smtpd_peername_lookup=no -o smtpd_timeout=30s"
|
||||
postconf -M "submission/inet=submission inet n - n - - smtpd -o syslog_name=postfix/submission -o smtpd_peername_lookup=no -o smtpd_tls_security_level=encrypt -o smtpd_tls_auth_only=yes -o smtpd_sasl_auth_enable=yes -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject"
|
||||
postconf -M "smtps/inet=smtps inet n - n - - smtpd -o syslog_name=postfix/smtps -o smtpd_peername_lookup=no -o smtpd_tls_wrappermode=yes -o smtpd_tls_auth_only=yes -o smtpd_sasl_auth_enable=yes -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject"
|
||||
postconf -M "pickup/unix=pickup unix n - y 60 1 pickup"
|
||||
postconf -M "cleanup/unix=cleanup unix n - y - 0 cleanup"
|
||||
postconf -M "qmgr/unix=qmgr unix n - n 300 1 qmgr"
|
||||
|
||||
install -d -o root -g postfix -m 750 /etc/postfix/sql
|
||||
|
||||
cat > /etc/postfix/sql/mysql-virtual-mailbox-maps.cf <<CONF
|
||||
hosts = 127.0.0.1
|
||||
user = ${DB_USER}
|
||||
password = ${DB_PASS}
|
||||
dbname = ${DB_NAME}
|
||||
query = SELECT 1
|
||||
FROM mail_users u
|
||||
JOIN domains d ON d.id = u.domain_id
|
||||
WHERE u.email = '%s' AND u.is_active = 1 AND d.is_active = 1
|
||||
LIMIT 1;
|
||||
CONF
|
||||
chown root:postfix /etc/postfix/sql/mysql-virtual-mailbox-maps.cf
|
||||
chmod 640 /etc/postfix/sql/mysql-virtual-mailbox-maps.cf
|
||||
|
||||
cat > /etc/postfix/sql/mysql-virtual-alias-maps.cf <<CONF
|
||||
hosts = 127.0.0.1
|
||||
user = ${DB_USER}
|
||||
password = ${DB_PASS}
|
||||
dbname = ${DB_NAME}
|
||||
query = SELECT destination
|
||||
FROM mail_aliases a
|
||||
JOIN domains d ON d.id = a.domain_id
|
||||
WHERE a.source = '%s' AND a.is_active = 1 AND d.is_active = 1
|
||||
LIMIT 1;
|
||||
CONF
|
||||
chown root:postfix /etc/postfix/sql/mysql-virtual-alias-maps.cf
|
||||
chmod 640 /etc/postfix/sql/mysql-virtual-alias-maps.cf
|
||||
|
||||
# Nur aktivieren – Start/Reload erst nach App/DB in 90-services.sh
|
||||
systemctl enable postfix >/dev/null 2>&1 || true
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#!/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
|
||||
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=vmail 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 postfix:postfix /var/spool/postfix /var/spool/postfix/private
|
||||
chmod 0755 /var/spool/postfix /var/spool/postfix/private
|
||||
|
||||
# Nur aktivieren – Start/Reload erst nach App/DB in 90-services.sh
|
||||
systemctl enable dovecot >/dev/null 2>&1 || true
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
log "Rspamd + OpenDKIM …"
|
||||
|
||||
cat > /etc/rspamd/local.d/worker-controller.inc <<'CONF'
|
||||
password = "admin";
|
||||
bind_socket = "127.0.0.1:11334";
|
||||
CONF
|
||||
systemctl enable --now rspamd || true
|
||||
|
||||
cat > /etc/opendkim.conf <<'CONF'
|
||||
Syslog yes
|
||||
UMask 002
|
||||
Mode sv
|
||||
Socket inet:8891@127.0.0.1
|
||||
Canonicalization relaxed/simple
|
||||
On-BadSignature accept
|
||||
On-Default accept
|
||||
On-KeyNotFound accept
|
||||
On-NoSignature accept
|
||||
LogWhy yes
|
||||
OversignHeaders From
|
||||
CONF
|
||||
systemctl enable --now opendkim || true
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
log "Nginx konfigurieren …"
|
||||
|
||||
NGINX_SITE="/etc/nginx/sites-available/${APP_USER}.conf"
|
||||
NGINX_SITE_LINK="/etc/nginx/sites-enabled/${APP_USER}.conf"
|
||||
ACME_ROOT="/var/www/letsencrypt"
|
||||
install -d -m 0755 "$ACME_ROOT"
|
||||
|
||||
# HTTP/2 prüfen
|
||||
NGINX_HTTP2_SUFFIX=""
|
||||
if nginx -V 2>&1 | grep -q http_v2; then
|
||||
NGINX_HTTP2_SUFFIX=" http2"
|
||||
fi
|
||||
|
||||
# PHP-FPM Socket oder TCP ermitteln und fastcgi_pass bauen
|
||||
detect_php_fpm_sock(){
|
||||
for v in 8.3 8.2 8.1 8.0 7.4; do
|
||||
s="/run/php/php${v}-fpm.sock"
|
||||
[[ -S "$s" ]] && { echo "unix:${s}"; return; }
|
||||
done
|
||||
[[ -S "/run/php/php-fpm.sock" ]] && { echo "unix:/run/php/php-fpm.sock"; return; }
|
||||
echo "127.0.0.1:9000"
|
||||
}
|
||||
PHP_FPM_TARGET="$(detect_php_fpm_sock)"
|
||||
if [[ "$PHP_FPM_TARGET" == unix:* ]]; then
|
||||
FASTCGI_PASS="fastcgi_pass ${PHP_FPM_TARGET#unix:};"
|
||||
else
|
||||
FASTCGI_PASS="fastcgi_pass ${PHP_FPM_TARGET};"
|
||||
fi
|
||||
|
||||
# Prüfen, ob UI-Zert vorhanden ist
|
||||
UI_CERT="/etc/ssl/ui/fullchain.pem"
|
||||
UI_KEY="/etc/ssl/ui/privkey.pem"
|
||||
SSL_ENABLED=0
|
||||
[[ -s "$UI_CERT" && -s "$UI_KEY" ]] && SSL_ENABLED=1
|
||||
|
||||
TPL="config/nginx/site.conf.tmpl"
|
||||
[[ -f "$TPL" ]] || die "Nginx-Template fehlt: $TPL"
|
||||
render="$(cat "$TPL")"
|
||||
|
||||
# --------- Bausteine, die in das Template eingesetzt werden ---------
|
||||
|
||||
# (A) HTTP-Body, wenn KEIN SSL → App direkt über Port 80
|
||||
HTTP_BODY_APP="$(cat <<'HTTP'
|
||||
root ${APP_DIR}/public;
|
||||
index index.php index.html;
|
||||
|
||||
access_log /var/log/nginx/${APP_USER}_access.log;
|
||||
error_log /var/log/nginx/${APP_USER}_error.log;
|
||||
|
||||
client_max_body_size 25m;
|
||||
|
||||
location / { try_files $uri $uri/ /index.php?$query_string; }
|
||||
location ~ \.php$ {
|
||||
include snippets/fastcgi-php.conf;
|
||||
__FASTCGI_PASS__
|
||||
try_files $uri =404;
|
||||
}
|
||||
location ^~ /livewire/ { try_files $uri /index.php?$query_string; }
|
||||
location ~* \.(jpg|jpeg|png|gif|css|js|ico|svg)$ { expires 30d; access_log off; }
|
||||
HTTP
|
||||
)"
|
||||
|
||||
# (B) HTTP-Body, wenn SSL → nur Redirect auf 443
|
||||
HTTP_BODY_REDIRECT='return 301 https://$host$request_uri;'
|
||||
|
||||
# (C) kompletter SSL-Serverblock (wird nur eingefügt, wenn SSL aktiv)
|
||||
SSL_BLOCK="$(cat <<'SSL'
|
||||
server {
|
||||
listen 443 ssl${NGINX_HTTP2_SUFFIX};
|
||||
listen [::]:443 ssl${NGINX_HTTP2_SUFFIX};
|
||||
server_name _;
|
||||
|
||||
ssl_certificate ${UI_CERT};
|
||||
ssl_certificate_key ${UI_KEY};
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
root ${APP_DIR}/public;
|
||||
index index.php index.html;
|
||||
|
||||
access_log /var/log/nginx/${APP_USER}_ssl_access.log;
|
||||
error_log /var/log/nginx/${APP_USER}_ssl_error.log;
|
||||
|
||||
client_max_body_size 25m;
|
||||
|
||||
location / { try_files $uri $uri/ /index.php?$query_string; }
|
||||
location ~ \.php$ {
|
||||
include snippets/fastcgi-php.conf;
|
||||
__FASTCGI_PASS__
|
||||
try_files $uri =404;
|
||||
}
|
||||
location ^~ /livewire/ { try_files $uri /index.php?$query_string; }
|
||||
location ~* \.(jpg|jpeg|png|gif|css|js|ico|svg)$ { expires 30d; access_log off; }
|
||||
|
||||
# WebSocket: Laravel Reverb
|
||||
location /ws/ {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_pass http://127.0.0.1:8080/;
|
||||
}
|
||||
|
||||
# Reverb HTTP API
|
||||
location /apps/ {
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_pass http://127.0.0.1:8080/apps/;
|
||||
}
|
||||
}
|
||||
SSL
|
||||
)"
|
||||
|
||||
# --------- Platzhalter ersetzen ---------
|
||||
if [[ $SSL_ENABLED -eq 1 ]]; then
|
||||
render="${render/__HTTP_BODY__/$HTTP_BODY_REDIRECT}"
|
||||
render="${render/__SSL_SERVER_BLOCK__/$SSL_BLOCK}"
|
||||
else
|
||||
render="${render/__HTTP_BODY__/$HTTP_BODY_APP}"
|
||||
render="${render/__SSL_SERVER_BLOCK__/}"
|
||||
fi
|
||||
|
||||
# Variablen & __FASTCGI_PASS__ im fertigen Render ersetzen
|
||||
render="$(echo "$render" \
|
||||
| sed "s|\${APP_DIR}|${APP_DIR}|g; s|\${APP_USER}|${APP_USER}|g; \
|
||||
s|\${UI_CERT}|${UI_CERT}|g; s|\${UI_KEY}|${UI_KEY}|g; \
|
||||
s|\${NGINX_HTTP2_SUFFIX}|${NGINX_HTTP2_SUFFIX}|g; \
|
||||
s|__FASTCGI_PASS__|${FASTCGI_PASS}|g")"
|
||||
|
||||
# Schreiben/aktivieren
|
||||
echo "$render" > "$NGINX_SITE"
|
||||
ln -sf "$NGINX_SITE" "$NGINX_SITE_LINK"
|
||||
|
||||
# Test & reload
|
||||
if nginx -t; then
|
||||
systemctl enable --now nginx >/dev/null 2>&1 || true
|
||||
systemctl reload nginx || true
|
||||
else
|
||||
die "nginx -t fehlgeschlagen – siehe /var/log/nginx/*.log"
|
||||
fi
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
log "App bereitstellen …"
|
||||
mkdir -p "$(dirname "$APP_DIR")"
|
||||
chown -R "$APP_USER":"$APP_GROUP" "$(dirname "$APP_DIR")"
|
||||
|
||||
# Repo holen oder Laravel anlegen – passe GIT_REPO/GIT_BRANCH bei Bedarf an
|
||||
GIT_REPO="${GIT_REPO:-https://example.com/your-repo-placeholder.git}"
|
||||
GIT_BRANCH="${GIT_BRANCH:-main}"
|
||||
|
||||
if [[ "${GIT_REPO}" == "https://example.com/your-repo-placeholder.git" ]]; then
|
||||
[[ -d "$APP_DIR" && -n "$(ls -A "$APP_DIR" 2>/dev/null || true)" ]] || \
|
||||
sudo -u "$APP_USER" -H bash -lc "cd /var/www && composer create-project laravel/laravel ${APP_USER} --no-interaction"
|
||||
else
|
||||
if [[ ! -d "${APP_DIR}/.git" ]]; then
|
||||
sudo -u "$APP_USER" -H bash -lc "git clone --depth=1 -b ${GIT_BRANCH} ${GIT_REPO} ${APP_DIR}"
|
||||
else
|
||||
sudo -u "$APP_USER" -H bash -lc "cd ${APP_DIR} && git fetch --depth=1 origin ${GIT_BRANCH} && git reset --hard origin/${GIT_BRANCH}"
|
||||
fi
|
||||
[[ -f "${APP_DIR}/composer.json" ]] && sudo -u "$APP_USER" -H bash -lc "cd ${APP_DIR} && composer install --no-interaction --prefer-dist"
|
||||
fi
|
||||
|
||||
ENV_FILE="${APP_DIR}/.env"
|
||||
sudo -u "$APP_USER" -H bash -lc "cd ${APP_DIR} && cp -n .env.example .env || true"
|
||||
grep -q '^APP_KEY=' "$ENV_FILE" || echo "APP_KEY=" >> "$ENV_FILE"
|
||||
sudo -u "$APP_USER" -H bash -lc "cd ${APP_DIR} && php artisan key:generate --force || true"
|
||||
|
||||
# APP_URL heuristisch
|
||||
APP_URL="http://${SERVER_PUBLIC_IPV4}"
|
||||
UI_CERT="/etc/ssl/ui/fullchain.pem"; UI_KEY="/etc/ssl/ui/privkey.pem"
|
||||
if [[ -f "$UI_CERT" && -f "$UI_KEY" && resolve_ok "$UI_HOST" ]]; then
|
||||
APP_URL="https://${UI_HOST}"
|
||||
fi
|
||||
|
||||
upsert_env APP_NAME "${APP_NAME}"
|
||||
upsert_env APP_URL "${APP_URL}"
|
||||
upsert_env APP_ENV "production"
|
||||
upsert_env APP_DEBUG "false"
|
||||
upsert_env APP_LOCALE "${APP_LOCALE}"
|
||||
upsert_env APP_FALLBACK_LOCALE "en"
|
||||
upsert_env SERVER_PUBLIC_IPV4 "${SERVER_PUBLIC_IPV4}"
|
||||
upsert_env SERVER_PUBLIC_IPV6 "${SERVER_PUBLIC_IPV6}"
|
||||
|
||||
upsert_env BASE_DOMAIN "${BASE_DOMAIN}"
|
||||
upsert_env UI_SUB "${UI_SUB}"
|
||||
upsert_env WEBMAIL_SUB "${WEBMAIL_SUB}"
|
||||
upsert_env SYSTEM_SUB "${SYSTEM_SUB}"
|
||||
upsert_env MTA_SUB "${MTA_SUB}"
|
||||
|
||||
upsert_env DB_CONNECTION "mysql"
|
||||
upsert_env DB_HOST "127.0.0.1"
|
||||
upsert_env DB_PORT "3306"
|
||||
upsert_env DB_DATABASE "${DB_NAME}"
|
||||
upsert_env DB_USERNAME "${DB_USER}"
|
||||
upsert_env DB_PASSWORD "${DB_PASS}"
|
||||
|
||||
upsert_env CACHE_DRIVER "redis"
|
||||
upsert_env SESSION_DRIVER "redis"
|
||||
upsert_env REDIS_CLIENT "phpredis"
|
||||
upsert_env REDIS_HOST "127.0.0.1"
|
||||
upsert_env REDIS_PORT "6379"
|
||||
upsert_env REDIS_PASSWORD "${REDIS_PASS:-}"
|
||||
|
||||
chown -R "$APP_USER":"$APP_GROUP" "$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"
|
||||
|
||||
sudo -u "$APP_USER" -H bash -lc "cd ${APP_DIR} && php artisan optimize:clear && php artisan config:cache"
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
log "systemd Units (Reverb / Scheduler / Queue) …"
|
||||
|
||||
cat > /etc/systemd/system/${APP_USER}-ws.service <<EOF
|
||||
[Unit]
|
||||
Description=${APP_NAME} WebSocket Backend
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=NODE_ENV=production WS_PORT=8080
|
||||
User=${APP_USER}
|
||||
Group=${APP_GROUP}
|
||||
WorkingDirectory=${APP_DIR}
|
||||
ExecStartPre=/usr/bin/bash -lc 'test -f .env'
|
||||
ExecStartPre=/usr/bin/bash -lc 'test -d vendor'
|
||||
ExecStart=/usr/bin/php artisan reverb:start --host=127.0.0.1 --port=8080 --no-interaction
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
StandardOutput=append:/var/log/${APP_USER}-ws.log
|
||||
StandardError=append:/var/log/${APP_USER}-ws.log
|
||||
KillSignal=SIGINT
|
||||
TimeoutStopSec=15
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat > /etc/systemd/system/${APP_USER}-schedule.service <<EOF
|
||||
[Unit]
|
||||
Description=${APP_NAME} Laravel Scheduler
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
User=${APP_USER}
|
||||
Group=${APP_GROUP}
|
||||
WorkingDirectory=${APP_DIR}
|
||||
ExecStartPre=/usr/bin/bash -lc 'test -f .env'
|
||||
ExecStartPre=/usr/bin/bash -lc 'test -d vendor'
|
||||
ExecStart=/usr/bin/php artisan schedule:work
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
StandardOutput=append:/var/log/${APP_USER}-schedule.log
|
||||
StandardError=append:/var/log/${APP_USER}-schedule.log
|
||||
KillSignal=SIGINT
|
||||
TimeoutStopSec=15
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat > /etc/systemd/system/${APP_USER}-queue.service <<EOF
|
||||
[Unit]
|
||||
Description=${APP_NAME} Queue Worker
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
User=${APP_USER}
|
||||
Group=${APP_GROUP}
|
||||
WorkingDirectory=${APP_DIR}
|
||||
ExecStartPre=/usr/bin/bash -lc 'test -f .env'
|
||||
ExecStartPre=/usr/bin/bash -lc 'test -d vendor'
|
||||
ExecStart=/usr/bin/php artisan queue:work --queue=default,notify --tries=1
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
StandardOutput=append:/var/log/${APP_USER}-queue.log
|
||||
StandardError=append:/var/log/${APP_USER}-queue.log
|
||||
KillSignal=SIGINT
|
||||
TimeoutStopSec=15
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
chown root:root /etc/systemd/system/${APP_USER}-*.service
|
||||
chmod 644 /etc/systemd/system/${APP_USER}-*.service
|
||||
touch /var/log/${APP_USER}-ws.log /var/log/${APP_USER}-schedule.log /var/log/${APP_USER}-queue.log
|
||||
chown ${APP_USER}:${APP_GROUP} /var/log/${APP_USER}-*.log
|
||||
chmod 664 /var/log/${APP_USER}-*.log
|
||||
|
||||
systemctl daemon-reload
|
||||
|
||||
# Optional: Reverb nur wenn vorhanden
|
||||
if sudo -u "$APP_USER" -H bash -lc "cd ${APP_DIR} && php artisan list --no-ansi | grep -qE '(^| )reverb:start( |$)'"; then
|
||||
systemctl enable --now ${APP_USER}-ws
|
||||
else
|
||||
systemctl disable --now ${APP_USER}-ws >/dev/null 2>&1 || true
|
||||
fi
|
||||
systemctl enable --now ${APP_USER}-schedule
|
||||
systemctl enable --now ${APP_USER}-queue
|
||||
|
||||
# Web stack neu laden
|
||||
systemctl reload nginx || true
|
||||
systemctl restart php*-fpm || true
|
||||
|
||||
# Postfix/Dovecot erst nach Migration reloaden
|
||||
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; }
|
||||
if db_ready; then
|
||||
systemctl reload postfix || true
|
||||
systemctl reload dovecot || true
|
||||
else
|
||||
echo "[i] DB noch nicht migriert – überspringe Postfix/Dovecot reload."
|
||||
fi
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
log "Monit konfigurieren …"
|
||||
cat > /etc/monit/monitrc <<'EOF'
|
||||
set daemon 60
|
||||
set logfile syslog facility log_daemon
|
||||
|
||||
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 tcp ssl then restart
|
||||
if failed port 587 type tcp then restart
|
||||
|
||||
check process dovecot with pidfile /run/dovecot/master.pid
|
||||
start program = "/bin/systemctl start dovecot"
|
||||
stop program = "/bin/systemctl stop dovecot"
|
||||
if failed port 143 type tcp then restart
|
||||
if failed port 993 type tcp ssl then restart
|
||||
|
||||
check process mariadb with pidfile /run/mysqld/mysqld.pid
|
||||
start program = "/bin/systemctl start mariadb"
|
||||
stop program = "/bin/systemctl stop mariadb"
|
||||
if failed port 3306 type tcp then restart
|
||||
|
||||
check process redis-server with pidfile /run/redis/redis-server.pid
|
||||
start program = "/bin/systemctl start redis-server"
|
||||
stop program = "/bin/systemctl stop redis-server"
|
||||
if failed port 6379 type tcp then restart
|
||||
|
||||
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 tcp ssl then restart
|
||||
EOF
|
||||
chmod 600 /etc/monit/monitrc
|
||||
monit -t && systemctl enable --now monit
|
||||
monit reload || true
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
log "MOTD installieren …"
|
||||
install -d /usr/local/bin
|
||||
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
|
||||
|
||||
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
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
source ./lib.sh
|
||||
|
||||
scheme="http"
|
||||
[[ -f /etc/ssl/ui/fullchain.pem && -f /etc/ssl/ui/privkey.pem ]] && scheme="https"
|
||||
|
||||
echo -e "
|
||||
${GREEN}${BAR}${NC}
|
||||
${GREEN}✔ ${APP_NAME} Bootstrap fertig${NC}
|
||||
${GREEN}${BAR}${NC}
|
||||
Admin-User: ${YELLOW}${ADMIN_USER}${NC}
|
||||
Admin-Mail: ${YELLOW}${ADMIN_EMAIL}${NC}
|
||||
Passwort: ${RED}${ADMIN_PASS}${NC}
|
||||
|
||||
Aufruf UI: ${CYAN}${scheme}://${SERVER_PUBLIC_IPV4}${NC}
|
||||
App Root: ${GREY}${APP_DIR}${NC}
|
||||
Nginx Site: ${GREY}/etc/nginx/sites-available/${APP_USER}.conf${NC}
|
||||
Mail-FQDN: ${GREY}${MAIL_HOSTNAME}${NC}
|
||||
"
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
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}"
|
||||
SYSTEM_SUB="${SYSTEM_SUB:-system}"
|
||||
|
||||
ADMIN_USER="${ADMIN_USER:-${APP_USER}}"
|
||||
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@localhost}"
|
||||
ADMIN_PASS="${ADMIN_PASS:-ChangeMe}"
|
||||
|
||||
DB_NAME="${DB_NAME:-${APP_USER}}"
|
||||
DB_USER="${DB_USER:-${APP_USER}}"
|
||||
DB_PASS="${DB_PASS:-$(openssl rand -hex 16)}"
|
||||
|
||||
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}"
|
||||
|
||||
read -r -p "Basisdomain (Enter=${BASE_DOMAIN}): " INP; BASE_DOMAIN="${INP:-$BASE_DOMAIN}"
|
||||
read -r -p "UI Subdomain (Enter=${UI_SUB}): " INP; UI_SUB="${INP:-$UI_SUB}"
|
||||
read -r -p "Webmail Subdomain (Enter=${WEBMAIL_SUB}): " INP; WEBMAIL_SUB="${INP:-$WEBMAIL_SUB}"
|
||||
read -r -p "Mailserver Subdomain (Enter=${MTA_SUB}): " INP; MTA_SUB="${INP:-$MTA_SUB}"
|
||||
|
||||
read -r -p "Zeitzone (Enter=${DEFAULT_TZ}): " INP; APP_TZ="${INP:-$DEFAULT_TZ}"
|
||||
read -r -p "Sprache [de/en] (Enter=${DEFAULT_LOCALE}): " INP; APP_LOCALE="${INP:-$DEFAULT_LOCALE}"
|
||||
|
||||
UI_HOST="$(join_host "$UI_SUB" "$BASE_DOMAIN")"
|
||||
WEBMAIL_HOST="$(join_host "$WEBMAIL_SUB" "$BASE_DOMAIN")"
|
||||
MAIL_HOSTNAME="$(join_host "$MTA_SUB" "$BASE_DOMAIN")"
|
||||
SYSTEM_HOSTNAME="$(join_host "$SYSTEM_SUB" "$BASE_DOMAIN")"
|
||||
|
||||
export APP_NAME APP_USER APP_GROUP APP_USER_PREFIX APP_DIR
|
||||
export BASE_DOMAIN UI_SUB WEBMAIL_SUB MTA_SUB SYSTEM_SUB
|
||||
export UI_HOST WEBMAIL_HOST MAIL_HOSTNAME SYSTEM_HOSTNAME
|
||||
export ADMIN_USER ADMIN_EMAIL ADMIN_PASS
|
||||
export DB_NAME DB_USER DB_PASS
|
||||
export SERVER_PUBLIC_IPV4 SERVER_PUBLIC_IPV6 APP_TZ APP_LOCALE
|
||||
|
||||
# ── Sequenz ────────────────────────────────────────────────────────────────
|
||||
for STEP in 10-provision 20-ssl 30-db 40-postfix 50-dovecot 60-rspamd-opendkim 70-nginx 80-app 90-services 95-monit 98-motd 99-summary
|
||||
do
|
||||
log ">>> Running ${STEP}.sh"
|
||||
bash "./${STEP}.sh"
|
||||
done
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ── Styling ────────────────────────────────────────────────────────────────
|
||||
GREEN="$(printf '\033[1;32m')"; YELLOW="$(printf '\033[1;33m')"
|
||||
RED="$(printf '\033[1;31m')"; CYAN="$(printf '\033[1;36m')"
|
||||
GREY="$(printf '\033[0;90m')"; NC="$(printf '\033[0m')"
|
||||
BAR="──────────────────────────────────────────────────────────────────────────────"
|
||||
log(){ echo -e "${GREEN}[+]${NC} $*"; }
|
||||
warn(){ echo -e "${YELLOW}[!]${NC} $*"; }
|
||||
err(){ echo -e "${RED}[x]${NC} $*"; }
|
||||
die(){ err "$*"; exit 1; }
|
||||
require_root(){ [[ "$(id -u)" -eq 0 ]] || die "Bitte als root ausführen."; }
|
||||
|
||||
header(){ echo -e "${CYAN}${BAR}${NC}
|
||||
${CYAN} 888b d888 d8b 888 888 888 888 888
|
||||
${CYAN} 8888b d8888 Y8P 888 888 o 888 888 888
|
||||
${CYAN} 88888b.d88888 888 888 d8b 888 888 888
|
||||
${CYAN} 888Y88888P888 8888b. 888 888 888 d888b 888 .d88b. 888 888888
|
||||
${CYAN} 888 Y888P 888 '88b 888 888 888d88888b888 d88''88b 888 888
|
||||
${CYAN} 888 Y8P 888 .d888888 888 888 88888P Y88888 888 888 888 888
|
||||
${CYAN} 888 ' 888 888 888 888 888 8888P Y8888 Y88..88P 888 Y88b.
|
||||
${CYAN} 888 888 'Y888888 888 888 888P Y888 'Y88P' 888 'Y888
|
||||
${CYAN}${BAR}${NC}\n"; }
|
||||
|
||||
detect_ip(){
|
||||
local ip
|
||||
ip="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}')" || true
|
||||
[[ -n "${ip:-}" ]] || ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||
[[ -n "${ip:-}" ]] || die "Konnte Server-IP nicht ermitteln."
|
||||
echo "$ip"
|
||||
}
|
||||
detect_ipv6(){
|
||||
local ip6
|
||||
ip6="$(ip -6 addr show scope global 2>/dev/null | awk '/inet6/{print $2}' | cut -d/ -f1 | head -n1)" || true
|
||||
[[ -n "${ip6:-}" ]] || ip6="$(hostname -I 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i ~ /:/){print $i; exit}}')" || true
|
||||
echo "${ip6:-}"
|
||||
}
|
||||
detect_timezone(){
|
||||
local tz
|
||||
if command -v timedatectl >/dev/null 2>&1; then
|
||||
tz="$(timedatectl show -p Timezone --value 2>/dev/null | tr -d '[:space:]')" || true
|
||||
[[ -n "${tz:-}" && "$tz" == */* ]] && { echo "$tz"; return; }
|
||||
fi
|
||||
[[ -r /etc/timezone ]] && { tz="$(sed -n '1p' /etc/timezone | tr -d '[:space:]')" || true; [[ "$tz" == */* ]] && { echo "$tz"; return; }; }
|
||||
if [[ -L /etc/localtime ]]; then
|
||||
tz="$(readlink -f /etc/localtime 2>/dev/null || true)"; tz="${tz#/usr/share/zoneinfo/}"
|
||||
[[ "$tz" == */* ]] && { echo "$tz"; return; }
|
||||
fi
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
tz="$(curl -fsSL --max-time 3 https://ipapi.co/timezone 2>/dev/null || true)"; [[ "$tz" == */* ]] && { echo "$tz"; return; }
|
||||
fi
|
||||
echo "UTC"
|
||||
}
|
||||
guess_locale_from_tz(){ case "${1:-UTC}" in
|
||||
Europe/Berlin|Europe/Vienna|Europe/Zurich|Europe/Luxembourg|Europe/Brussels|Europe/Amsterdam) echo "de";;
|
||||
*) echo "en";; esac; }
|
||||
|
||||
resolve_ok(){ local host="$1"; getent ahosts "$host" | awk '{print $1}' | sort -u | grep -q -F "${SERVER_PUBLIC_IPV4:-}" ; }
|
||||
join_host(){ local sub="$1" base="$2"; [[ -z "$sub" ]] && echo "$base" || echo "$sub.$base"; }
|
||||
|
||||
upsert_env(){ # upsert in $ENV_FILE
|
||||
local k="$1" v="$2" ek ev
|
||||
ek="$(printf '%s' "$k" | sed -e 's/[.[\*^$(){}+?|/]/\\&/g')"
|
||||
ev="$(printf '%s' "$v" | sed -e 's/[&/]/\\&/g')"
|
||||
if grep -qE "^[#[:space:]]*${ek}=" "$ENV_FILE" 2>/dev/null; then
|
||||
sed -Ei "s|^[#[:space:]]*${ek}=.*|${k}=${ev}|g" "$ENV_FILE"
|
||||
else
|
||||
printf '%s=%s\n' "$k" "$v" >> "$ENV_FILE"
|
||||
fi
|
||||
}
|
||||
Loading…
Reference in New Issue