Files
archivmail/install.sh
T
sysops 48e04f36fd fix(installer): Lücken aus Gap-Report geschlossen
- rsync zum apt-Paket-Block hinzugefügt
- DEBIAN_FRONTEND=noninteractive gesetzt (keine debconf-Interaktion)
- go PATH-Fix: Debian-spezifische Pfade in /usr/lib/go-*/bin ergänzen
  (update.sh + install.sh symlink-Fallback)
- TLS-Zertifikat: selbstsigniertes RSA-4096 Cert via hostname -f,
  /etc/ssl/archivmail/ anlegen + Permissions (640, root:archivmail)
- nginx: HTTPS von Anfang an (HTTP→HTTPS Redirect + TLS-Block statt HTTP-only)
- config.yml-Template vollständig:
  - smtp.enabled, smtp.domain (hostname -f), smtp.tls_cert/tls_key
  - imap_server (enabled, bind :993, tls_cert/tls_key)
  - api.trusted_proxies, api.secure_cookies: true
  - Vorhandenes config.yml wird nicht überschrieben
- systemd archivmail.service: AmbientCapabilities=CAP_NET_BIND_SERVICE
  (für privilegierten Port 993 als non-root User)
  NoNewPrivileges=false (erforderlich für AmbientCapabilities)
  ReadOnlyPaths um /etc/ssl/archivmail ergänzt
- systemctl enable am Ende des Installers (ohne --now)
- update.sh nach /opt/archivmail/ kopieren + erstes Deployment direkt anstoßen
- Abschlussbericht: FQDN, HTTPS/IMAP/SMTP URLs, TLS-Hinweis

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 01:03:57 +01:00

361 lines
14 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# archivmail Server-Installer
# Unterstützte Systeme: Debian 12 / 13
# Aufruf: bash install.sh
# 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} $*"; }
info() { echo -e "${BLUE}[..]${NC} $*"; }
warn() { echo -e "${YELLOW}[!!]${NC} $*"; }
die() { echo -e "${RED}[ERR]${NC} $*" >&2; exit 1; }
[[ $EUID -eq 0 ]] || die "Bitte als root ausführen: sudo bash install.sh"
DB_PASSWORD="${DB_PASSWORD:-$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)}"
API_SECRET="${API_SECRET:-$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | head -c 64)}"
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.1 ║"
echo " ╚══════════════════════════════════════╝"
echo ""
info "Hostname: $FQDN"
echo ""
# ── 1. Pakete ─────────────────────────────────────────────────────────────────
info "Installiere Systempakete..."
apt-get update -qq
apt-get install -y -qq \
golang-go nodejs npm postgresql nginx \
libxapian-dev pkg-config build-essential \
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 \
&& log "Benutzer '$AM_USER' existiert bereits" \
|| { useradd --system --shell /bin/false --home "$STORE_DIR" --create-home "$AM_USER"; log "Benutzer angelegt"; }
# ── 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" "$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"
log "Verzeichnisse erstellt"
# ── 4. Keyfile ────────────────────────────────────────────────────────────────
info "Generiere Verschlüsselungs-Keyfile..."
if [ ! -f "$CONFIG_DIR/keyfile" ]; then
openssl rand -base64 32 > "$CONFIG_DIR/keyfile"
chmod 400 "$CONFIG_DIR/keyfile"
chown "$AM_USER:$AM_USER" "$CONFIG_DIR/keyfile"
log "Keyfile generiert: $CONFIG_DIR/keyfile"
else
log "Keyfile existiert bereits wird nicht überschrieben"
fi
# ── 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
su -c "psql -tc \"SELECT 1 FROM pg_roles WHERE rolname='archivmail'\" | grep -q 1 \
&& psql -c \"ALTER USER archivmail WITH PASSWORD '$DB_PASSWORD'\" \
|| psql -c \"CREATE USER archivmail WITH PASSWORD '$DB_PASSWORD'\"" postgres
su -c "psql -tc \"SELECT 1 FROM pg_database WHERE datname='archivmail'\" | grep -q 1 || \
psql -c \"CREATE DATABASE archivmail OWNER archivmail\"" postgres
su -c "psql archivmail -c \"GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO archivmail;\"" postgres
su -c "psql archivmail -c \"GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO archivmail;\"" postgres
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 eingerichtet"
log "Standard-Benutzer werden beim ersten Daemon-Start angelegt"
# ── 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:
api_port: 8080
smtp_port: 2525
database:
host: 127.0.0.1
port: 5432
name: archivmail
user: archivmail
password: ${DB_PASSWORD}
sslmode: disable
storage:
store_path: ${STORE_DIR}/store
astore_path: ${STORE_DIR}/astore
xapian_path: ${STORE_DIR}/xapian
keyfile: ${CONFIG_DIR}/keyfile
api:
bind: ":8080"
secret: ${API_SECRET}
trusted_proxies:
- 127.0.0.1
secure_cookies: true
index:
path: ${STORE_DIR}/xapian
backend: xapian
batch_size: 100
audit:
log_path: ${LOG_DIR}/audit.log
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
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 ${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 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_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;
}
NGINX
ln -sf /etc/nginx/sites-available/archivmail /etc/nginx/sites-enabled/archivmail
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl enable nginx --quiet
systemctl restart nginx
log "Nginx konfiguriert (HTTP→HTTPS, TLS)"
# ── 9. logrotate ──────────────────────────────────────────────────────────────
cat > /etc/logrotate.d/archivmail << LOGROTATE
${LOG_DIR}/audit.log {
daily
rotate 365
compress
delaycompress
missingok
notifempty
create 640 ${AM_USER} ${AM_USER}
}
LOGROTATE
log "logrotate konfiguriert"
# ── 10. systemd Units ─────────────────────────────────────────────────────────
info "Erstelle systemd Units..."
cat > /etc/systemd/system/archivmail.service << UNIT
[Unit]
Description=archivmail Mail Archive Daemon
After=network.target postgresql.service
Requires=postgresql.service
[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=false
ProtectSystem=strict
ReadWritePaths=${STORE_DIR} ${LOG_DIR}
ReadOnlyPaths=${CONFIG_DIR} ${SSL_DIR}
[Install]
WantedBy=multi-user.target
UNIT
cat > /etc/systemd/system/archivmail-web.service << UNIT
[Unit]
Description=archivmail Web Frontend
After=network.target archivmail.service
[Service]
Type=simple
User=${AM_USER}
Group=${AM_USER}
WorkingDirectory=${INSTALL_DIR}/web
ExecStart=/usr/bin/node server.js
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=NEXT_PUBLIC_API_URL=http://127.0.0.1:8080
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=archivmail-web
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
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 ""
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:"
echo " Host: 127.0.0.1:5432 / archivmail"
printf " Passwort: %s\n" "$DB_PASSWORD"
echo ""
echo " Standard-Zugangsdaten (nach Deployment ändern!):"
echo " Admin: admin@archivmail / archivmailrockz"
echo " Auditor: auditor@archivmail / archivmailrockz"
echo ""
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!"
echo ""