diff --git a/install.sh b/install.sh index f17c1cf..1822a3b 100755 --- a/install.sh +++ b/install.sh @@ -5,6 +5,7 @@ # Mit eigenem DB-Passwort: DB_PASSWORD=geheim bash install.sh set -euo pipefail +export DEBIAN_FRONTEND=noninteractive RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' log() { echo -e "${GREEN}[OK]${NC} $*"; } @@ -20,13 +21,18 @@ INSTALL_DIR="/opt/archivmail" STORE_DIR="/var/archivmail" LOG_DIR="/var/log/archivmail" CONFIG_DIR="/etc/archivmail" +SSL_DIR="/etc/ssl/archivmail" AM_USER="archivmail" +FQDN="$(hostname -f 2>/dev/null || hostname)" +REPO_URL="${REPO_URL:-https://gitea.perlbach24.de/scripte/archivmail.git}" echo "" echo " ╔══════════════════════════════════════╗" -echo " ║ archivmail Installer v1.0 ║" +echo " ║ archivmail Installer v1.1 ║" echo " ╚══════════════════════════════════════╝" echo "" +info "Hostname: $FQDN" +echo "" # ── 1. Pakete ───────────────────────────────────────────────────────────────── info "Installiere Systempakete..." @@ -34,9 +40,18 @@ apt-get update -qq apt-get install -y -qq \ golang-go nodejs npm postgresql nginx \ libxapian-dev pkg-config build-essential \ - curl git logrotate openssl + curl git rsync logrotate openssl log "Pakete installiert" +# go im PATH sicherstellen (Debian legt binary nicht immer in /usr/bin) +if ! command -v go >/dev/null 2>&1; then + GO_BIN=$(find /usr/lib/go-*/bin /usr/local/go/bin -name "go" 2>/dev/null | head -1) + [[ -n "$GO_BIN" ]] || die "go binary nicht gefunden nach Installation" + ln -sf "$GO_BIN" /usr/local/bin/go + log "go binary verlinkt: $GO_BIN → /usr/local/bin/go" +fi +log "go $(go version | awk '{print $3}')" + # ── 2. Systembenutzer ───────────────────────────────────────────────────────── info "Lege Systembenutzer '$AM_USER' an..." id "$AM_USER" &>/dev/null \ @@ -46,7 +61,7 @@ id "$AM_USER" &>/dev/null \ # ── 3. Verzeichnisstruktur ──────────────────────────────────────────────────── info "Erstelle Verzeichnisstruktur..." mkdir -p "$STORE_DIR/store" "$STORE_DIR/astore" "$STORE_DIR/xapian" -mkdir -p "$CONFIG_DIR" "$LOG_DIR" "$INSTALL_DIR" "$INSTALL_DIR/web" +mkdir -p "$CONFIG_DIR" "$LOG_DIR" "$INSTALL_DIR" "$INSTALL_DIR/web" "$SSL_DIR" chown -R "$AM_USER:$AM_USER" "$STORE_DIR" "$LOG_DIR" chmod 755 "$STORE_DIR" chmod 700 "$STORE_DIR/store" "$STORE_DIR/astore" "$STORE_DIR/xapian" @@ -63,7 +78,25 @@ else log "Keyfile existiert bereits – wird nicht überschrieben" fi -# ── 5. PostgreSQL ───────────────────────────────────────────────────────────── +# ── 5. TLS-Zertifikat ───────────────────────────────────────────────────────── +info "Erstelle selbstsigniertes TLS-Zertifikat..." +if [ ! -f "$SSL_DIR/archivmail.crt" ]; then + SERVER_IP="$(hostname -I | awk '{print $1}')" + openssl req -x509 -nodes -days 3650 -newkey rsa:4096 \ + -keyout "$SSL_DIR/archivmail.key" \ + -out "$SSL_DIR/archivmail.crt" \ + -subj "/CN=${FQDN}/O=archivmail/C=DE" \ + -addext "subjectAltName=DNS:${FQDN},DNS:$(hostname -s),IP:${SERVER_IP}" \ + 2>/dev/null + chmod 640 "$SSL_DIR/archivmail.key" + chmod 644 "$SSL_DIR/archivmail.crt" + chown "root:$AM_USER" "$SSL_DIR/archivmail.key" + log "TLS-Zertifikat erstellt: $SSL_DIR/archivmail.crt (FQDN: $FQDN, IP: $SERVER_IP)" +else + log "TLS-Zertifikat existiert bereits – wird nicht überschrieben" +fi + +# ── 6. PostgreSQL ───────────────────────────────────────────────────────────── info "Richte PostgreSQL ein..." systemctl enable postgresql --quiet systemctl start postgresql @@ -79,12 +112,12 @@ su -c "psql archivmail -c \"GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA publ su -c "psql archivmail -c \"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO archivmail;\"" postgres su -c "psql archivmail -c \"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO archivmail;\"" postgres -log "PostgreSQL-Schema angelegt" - +log "PostgreSQL eingerichtet" log "Standard-Benutzer werden beim ersten Daemon-Start angelegt" -# ── 6. Konfiguration ────────────────────────────────────────────────────────── +# ── 7. Konfiguration ────────────────────────────────────────────────────────── info "Erstelle Konfigurationsdatei..." +if [ ! -f "$CONFIG_DIR/config.yml" ]; then cat > "$CONFIG_DIR/config.yml" << CONFIG # archivmail Konfiguration – generiert am $(date -u +%Y-%m-%dT%H:%M:%SZ) server: @@ -108,6 +141,9 @@ storage: api: bind: ":8080" secret: ${API_SECRET} + trusted_proxies: + - 127.0.0.1 + secure_cookies: true index: path: ${STORE_DIR}/xapian @@ -119,38 +155,77 @@ audit: retention_days: 0 smtp: + enabled: true bind: ":2525" + domain: "${FQDN}" + tls_cert: ${SSL_DIR}/archivmail.crt + tls_key: ${SSL_DIR}/archivmail.key allowed_ips: - 127.0.0.1 -CONFIG -chmod 640 "$CONFIG_DIR/config.yml" -chown "root:$AM_USER" "$CONFIG_DIR/config.yml" -log "Konfiguration: $CONFIG_DIR/config.yml" -# ── 7. Nginx ────────────────────────────────────────────────────────────────── -info "Konfiguriere Nginx..." -cat > /etc/nginx/sites-available/archivmail << 'NGINX' +imap_server: + enabled: true + bind: ":993" + tls_cert: ${SSL_DIR}/archivmail.crt + tls_key: ${SSL_DIR}/archivmail.key +CONFIG + chmod 640 "$CONFIG_DIR/config.yml" + chown "root:$AM_USER" "$CONFIG_DIR/config.yml" + log "Konfiguration erstellt: $CONFIG_DIR/config.yml" +else + log "config.yml existiert bereits – wird nicht überschrieben" +fi + +# ── 8. Nginx (HTTP + HTTPS) ──────────────────────────────────────────────────── +info "Konfiguriere Nginx (HTTP → HTTPS Redirect + TLS)..." +cat > /etc/nginx/sites-available/archivmail << NGINX +# HTTP → HTTPS Redirect server { listen 80; - server_name _; + server_name ${FQDN} _; + return 301 https://\$host\$request_uri; +} + +# HTTPS +server { + listen 443 ssl; + http2 on; + server_name ${FQDN} _; + + ssl_certificate ${SSL_DIR}/archivmail.crt; + ssl_certificate_key ${SSL_DIR}/archivmail.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + add_header Strict-Transport-Security "max-age=31536000" always; + add_header X-Content-Type-Options nosniff always; + add_header X-Frame-Options SAMEORIGIN always; + + location /api/ { + proxy_pass http://127.0.0.1:8080; + proxy_http_version 1.1; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + client_max_body_size 512M; + } location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; + proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_cache_bypass $http_upgrade; - } - location /api/ { - proxy_pass http://127.0.0.1:8080; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - client_max_body_size 512M; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_cache_bypass \$http_upgrade; } + access_log /var/log/nginx/archivmail.access.log; error_log /var/log/nginx/archivmail.error.log; } @@ -160,9 +235,9 @@ rm -f /etc/nginx/sites-enabled/default nginx -t systemctl enable nginx --quiet systemctl restart nginx -log "Nginx konfiguriert" +log "Nginx konfiguriert (HTTP→HTTPS, TLS)" -# ── 8. logrotate ────────────────────────────────────────────────────────────── +# ── 9. logrotate ────────────────────────────────────────────────────────────── cat > /etc/logrotate.d/archivmail << LOGROTATE ${LOG_DIR}/audit.log { daily @@ -176,7 +251,7 @@ ${LOG_DIR}/audit.log { LOGROTATE log "logrotate konfiguriert" -# ── 9. systemd Units ────────────────────────────────────────────────────────── +# ── 10. systemd Units ───────────────────────────────────────────────────────── info "Erstelle systemd Units..." cat > /etc/systemd/system/archivmail.service << UNIT [Unit] @@ -188,16 +263,18 @@ Requires=postgresql.service Type=simple User=${AM_USER} Group=${AM_USER} +AmbientCapabilities=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE ExecStart=${INSTALL_DIR}/archivmail --config ${CONFIG_DIR}/config.yml Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal SyslogIdentifier=archivmail -NoNewPrivileges=true +NoNewPrivileges=false ProtectSystem=strict ReadWritePaths=${STORE_DIR} ${LOG_DIR} -ReadOnlyPaths=${CONFIG_DIR} +ReadOnlyPaths=${CONFIG_DIR} ${SSL_DIR} [Install] WantedBy=multi-user.target @@ -228,7 +305,22 @@ WantedBy=multi-user.target UNIT systemctl daemon-reload -log "systemd Units erstellt" +systemctl enable archivmail archivmail-web --quiet +log "systemd Units erstellt und aktiviert" + +# ── 11. update.sh installieren und erstes Deployment ────────────────────────── +info "Installiere update.sh und führe erstes Deployment durch..." +curl -fsSL "${REPO_URL/\.git/}/raw/branch/main/update.sh" -o "$INSTALL_DIR/update.sh" 2>/dev/null \ + || { warn "update.sh konnte nicht von Gitea geladen werden – überspringe Deployment"; } + +if [ -f "$INSTALL_DIR/update.sh" ]; then + chmod +x "$INSTALL_DIR/update.sh" + log "update.sh installiert: $INSTALL_DIR/update.sh" + info "Führe erstes Deployment durch (Build + Start)..." + bash "$INSTALL_DIR/update.sh" +else + warn "update.sh fehlt — manuell ausführen: bash $INSTALL_DIR/update.sh" +fi # ── Abschlussbericht ────────────────────────────────────────────────────────── echo "" @@ -236,11 +328,14 @@ echo " ╔═══════════════════════ echo " ║ Installation abgeschlossen! ║" echo " ╚══════════════════════════════════════════════════════════╝" echo "" +echo " Hostname (FQDN): $FQDN" +echo "" echo " Pfade:" echo " Binaries: $INSTALL_DIR/" echo " Mail-Speicher: $STORE_DIR/" echo " Konfiguration: $CONFIG_DIR/config.yml" echo " Keyfile: $CONFIG_DIR/keyfile (chmod 400 – sicher aufbewahren!)" +echo " TLS-Zertifikat: $SSL_DIR/archivmail.crt" echo " Logs: $LOG_DIR/" echo "" echo " Datenbank:" @@ -251,10 +346,14 @@ echo " Standard-Zugangsdaten (nach Deployment ändern!):" echo " Admin: admin@archivmail / archivmailrockz" echo " Auditor: auditor@archivmail / archivmailrockz" echo "" -echo " Nächste Schritte nach Deployment:" -echo " 1. cp archivmail $INSTALL_DIR/" -echo " 2. cp -r web/ $INSTALL_DIR/web/" -echo " 3. systemctl enable --now archivmail archivmail-web" +echo " Dienste:" +echo " Web (HTTPS): https://$FQDN" +echo " IMAP (TLS): $FQDN:993" +echo " SMTP: $FQDN:2525" +echo "" +echo " Hinweis: Das TLS-Zertifikat ist selbstsigniert." +echo " Zertifikat importieren oder im Browser-Ausnahme hinzufügen." +echo " Für ein vertrauenswürdiges Zertifikat: Admin → Zertifikat → Let's Encrypt" echo "" warn "DB-Passwort steht in $CONFIG_DIR/config.yml (chmod 640, root:archivmail)" warn "Standardpasswörter unbedingt nach dem ersten Login ändern!" diff --git a/update.sh b/update.sh index cd3623a..92ebde9 100755 --- a/update.sh +++ b/update.sh @@ -41,10 +41,14 @@ fi # ── Voraussetzungen prüfen ──────────────────────────────────────────────── +# Debian legt go nicht immer in /usr/bin — bekannte Pfade ergänzen +export PATH="$PATH:/usr/local/go/bin:/usr/lib/go/bin" +for d in /usr/lib/go-*/bin; do export PATH="$PATH:$d"; done + command -v git >/dev/null || die "git nicht gefunden" command -v node >/dev/null || die "node nicht gefunden" command -v npm >/dev/null || die "npm nicht gefunden" -command -v go >/dev/null || die "go nicht gefunden" +command -v go >/dev/null || die "go nicht gefunden — apt-get install golang-go" # ── Quellcode holen ───────────────────────────────────────────────────────