Manticore hat das Debian-Paketschema geändert: früher mehrere manticoresearch_*-Pakete unter pool/main/m/manticoresearch/, seit ~v25 ein einziges "manticore"-Paket unter dists/bookworm/main/binary-ARCH/. Beide Skripte waren zudem hart auf die veraltete Version 6.3.6 gepinnt (aktuell: 27.1.5). GitHub-Release-Fallback entfernt, da GitHub-Releases inzwischen keine .deb-Assets mehr anhängen (leeres assets[], per API verifiziert) — repo.manticoresearch.com ist der einzige funktionierende Weg. Neue Download-URL + Paket-Metadaten (Name/Version/Architektur) gegen den echten Server verifiziert, beide Skripte mit bash -n auf Syntaxfehler geprüft. Betrifft nur Neuinstallationen — bestehende Installationen mit bereits laufendem Manticore überspringen den Installationsblock unverändert.
349 lines
15 KiB
Bash
Executable File
349 lines
15 KiB
Bash
Executable File
#!/bin/bash
|
|
# archivmail Updater
|
|
# Zieht die neueste Version aus Gitea, baut Frontend + Backend und startet Dienste neu.
|
|
#
|
|
# Aufruf (auf dem Server als root):
|
|
# bash /opt/archivmail/update.sh
|
|
#
|
|
# Oder direkt von Gitea laden und ausführen:
|
|
# curl -fsSL https://gitea.perlbach24.de/scripte/archivmail/raw/branch/main/update.sh | bash
|
|
|
|
set -euo pipefail
|
|
|
|
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 update.sh"
|
|
|
|
REPO_URL="${REPO_URL:-https://gitea.perlbach24.de/scripte/archivmail.git}"
|
|
INSTALL_DIR="/opt/archivmail"
|
|
BUILD_DIR="/opt/archivmail/_build"
|
|
FRONTEND_DIR="/opt/archivmail/web"
|
|
BIN_DIR="/opt/archivmail/bin"
|
|
|
|
echo ""
|
|
echo " ╔══════════════════════════════════════╗"
|
|
echo " ║ archivmail Updater ║"
|
|
echo " ╚══════════════════════════════════════╝"
|
|
echo ""
|
|
|
|
# ── Script selbst aktualisieren ──────────────────────────────────────────
|
|
|
|
SCRIPT_URL="https://gitea.perlbach24.de/scripte/archivmail/raw/branch/main/update.sh"
|
|
SELF="$INSTALL_DIR/update.sh"
|
|
if [[ -f "$SELF" ]] && command -v curl >/dev/null; then
|
|
curl -fsSL "$SCRIPT_URL" -o "$SELF.new" 2>/dev/null && mv "$SELF.new" "$SELF" && chmod +x "$SELF" \
|
|
&& info "Script aktualisiert" || rm -f "$SELF.new"
|
|
fi
|
|
|
|
# ── Go: Version sicherstellen (OS-versions-agnostisch) ───────────────────
|
|
# Go wird unter /usr/local/go installiert — unabhängig von apt und Debian-Version.
|
|
# Das gilt nach einem OS-Upgrade auf Debian 14+ genauso wie auf trixie.
|
|
|
|
GO_REQUIRED="1.24.4"
|
|
export PATH="$PATH:/usr/local/go/bin"
|
|
|
|
_go_ok=0
|
|
if command -v go >/dev/null 2>&1; then
|
|
_go_installed=$(go version 2>/dev/null | grep -oP 'go\K[0-9]+\.[0-9]+' | head -1)
|
|
_go_major=${_go_installed%%.*}
|
|
_go_minor=${_go_installed#*.}
|
|
# >= 1.24 gilt als ausreichend
|
|
if [[ "$_go_major" -gt 1 ]] || [[ "$_go_major" -eq 1 && "$_go_minor" -ge 24 ]]; then
|
|
_go_ok=1
|
|
fi
|
|
fi
|
|
|
|
if [[ $_go_ok -eq 0 ]]; then
|
|
info "Go < 1.24 oder nicht gefunden — installiere Go ${GO_REQUIRED} von upstream..."
|
|
_go_arch="amd64"
|
|
[[ "$(uname -m)" == "aarch64" ]] && _go_arch="arm64"
|
|
curl -fsSL "https://dl.google.com/go/go${GO_REQUIRED}.linux-${_go_arch}.tar.gz" \
|
|
| tar -C /usr/local -xz
|
|
ln -sf /usr/local/go/bin/go /usr/local/bin/go
|
|
ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
|
|
log "Go $(go version | awk '{print $3}') installiert"
|
|
else
|
|
log "Go $(go version | awk '{print $3}') OK"
|
|
fi
|
|
|
|
# ── Sonstige Voraussetzungen ──────────────────────────────────────────────
|
|
|
|
command -v git >/dev/null || die "git nicht gefunden — apt-get install git"
|
|
command -v node >/dev/null || die "node nicht gefunden — apt-get install nodejs"
|
|
command -v npm >/dev/null || die "npm nicht gefunden — apt-get install npm"
|
|
|
|
# ── Manticore Search prüfen / installieren ────────────────────────────────
|
|
# Paket ist an bookworm gebunden — funktioniert auch auf trixie und Debian 14+,
|
|
# da Manticore kein OS-spezifisches ABI nutzt (repo.manticoresearch.com hat
|
|
# kein eigenes trixie-Repo, siehe Release-Notes ab v13.6.7 "Added support for
|
|
# Debian 13 Trixie" — das bezieht sich auf Lauffähigkeit, nicht auf ein neues
|
|
# Repo). Seit ~v25 ist "manticoresearch" ein einziges "manticore"-Paket
|
|
# (vorher mehrere manticore-server/-tools/-dev-Pakete) — Paketname und
|
|
# Pfadstruktur im Repo haben sich entsprechend geändert. GitHub-Releases
|
|
# liefern seit einiger Zeit keine .deb-Assets mehr (leeres assets[]), daher
|
|
# kein Fallback mehr dorthin — repo.manticoresearch.com ist der einzige Weg.
|
|
#
|
|
# Version manuell pinnen (wie hier) statt "latest" dynamisch aus der
|
|
# Packages-Datei zu parsen: vorhersagbarer, kein Risiko durch Parsing-Format-
|
|
# Änderungen im Repo. Zum Aktualisieren: aktuelle Version+Filename unter
|
|
# https://repo.manticoresearch.com/repository/manticoresearch_bookworm/dists/bookworm/main/binary-amd64/Packages
|
|
# nachschlagen (letzter "Package: manticore"-Block).
|
|
_MANTICORE_VERSION="27.1.5-26061911-5a1cf9399"
|
|
|
|
if ! command -v searchd >/dev/null 2>&1 && ! systemctl is-active --quiet manticore 2>/dev/null; then
|
|
info "Manticore Search nicht gefunden — installiere Version ${_MANTICORE_VERSION}..."
|
|
_mc_arch="amd64"
|
|
[[ "$(uname -m)" == "aarch64" ]] && _mc_arch="arm64"
|
|
wget -q -O /tmp/manticore.deb \
|
|
"https://repo.manticoresearch.com/repository/manticoresearch_bookworm/dists/bookworm/main/binary-${_mc_arch}/manticore_${_MANTICORE_VERSION}_${_mc_arch}.deb" \
|
|
|| true
|
|
if [[ -f /tmp/manticore.deb ]]; then
|
|
dpkg -i /tmp/manticore.deb 2>/dev/null || apt-get install -f -y -qq 2>/dev/null || true
|
|
rm -f /tmp/manticore.deb
|
|
log "Manticore Search installiert"
|
|
else
|
|
warn "Manticore Search konnte nicht automatisch installiert werden — bitte manuell installieren"
|
|
warn "Siehe: https://manticoresearch.com/install/"
|
|
fi
|
|
fi
|
|
|
|
if systemctl list-unit-files manticore.service >/dev/null 2>&1; then
|
|
systemctl enable manticore 2>/dev/null || true
|
|
systemctl is-active --quiet manticore || systemctl start manticore 2>/dev/null || warn "Manticore-Dienst konnte nicht gestartet werden"
|
|
systemctl is-active --quiet manticore && log "Manticore Search läuft"
|
|
fi
|
|
|
|
# ── OCR-Tools (PROJ-35: tesseract + poppler) ──────────────────────────────
|
|
# Optional: ohne diese Tools fällt OCR auf "deaktiviert" zurück, kein Abbruch.
|
|
if ! command -v tesseract >/dev/null 2>&1 || ! command -v pdftotext >/dev/null 2>&1; then
|
|
info "Installiere OCR-Tools (tesseract, poppler-utils)..."
|
|
apt-get install -y tesseract-ocr tesseract-ocr-deu poppler-utils 2>/dev/null || \
|
|
warn "OCR-Tools konnten nicht installiert werden — OCR wird deaktiviert"
|
|
fi
|
|
if command -v tesseract >/dev/null 2>&1 && command -v pdftotext >/dev/null 2>&1; then
|
|
log "OCR-Tools verfügbar (tesseract $(tesseract --version 2>&1 | head -1 | awk '{print $2}'))"
|
|
fi
|
|
|
|
# ── Quellcode holen ───────────────────────────────────────────────────────
|
|
|
|
if [[ -d "$BUILD_DIR/.git" ]]; then
|
|
info "Aktualisiere Quellcode aus Gitea..."
|
|
git config --global --add safe.directory "$BUILD_DIR" 2>/dev/null || true
|
|
git -C "$BUILD_DIR" fetch origin
|
|
git -C "$BUILD_DIR" reset --hard origin/main
|
|
log "Quellcode aktualisiert ($(git -C "$BUILD_DIR" log -1 --format='%h %s'))"
|
|
else
|
|
info "Lade Quellcode von $REPO_URL ..."
|
|
mkdir -p "$BUILD_DIR"
|
|
git clone "$REPO_URL" "$BUILD_DIR"
|
|
log "Quellcode geladen"
|
|
fi
|
|
|
|
# ── Go Backend bauen ──────────────────────────────────────────────────────
|
|
|
|
info "Baue Go Backend..."
|
|
cd "$BUILD_DIR"
|
|
go mod tidy && go mod download
|
|
CGO_ENABLED=0 go build -buildvcs=false -o "$BUILD_DIR/archivmail-new" ./cmd/archivmail/
|
|
log "Go Backend gebaut"
|
|
|
|
# ── Next.js Frontend bauen ────────────────────────────────────────────────
|
|
|
|
info "Installiere Node-Abhängigkeiten..."
|
|
npm ci --prefer-offline 2>/dev/null || npm ci
|
|
log "Node-Abhängigkeiten installiert"
|
|
|
|
info "Baue Next.js Frontend..."
|
|
npm run build
|
|
log "Frontend gebaut"
|
|
|
|
# ── Dienste stoppen ───────────────────────────────────────────────────────
|
|
|
|
info "Stoppe Dienste..."
|
|
systemctl stop archivmail-web 2>/dev/null || warn "archivmail-web nicht aktiv"
|
|
systemctl stop archivmail 2>/dev/null || warn "archivmail nicht aktiv"
|
|
|
|
# ── Manticore als Standard-Backend in config.yml setzen ──────────────────
|
|
CONFIG_FILE="/etc/archivmail/config.yml"
|
|
if [[ -f "$CONFIG_FILE" ]]; then
|
|
# Backend auf manticore umstellen falls noch nicht gesetzt
|
|
if grep -q 'backend:' "$CONFIG_FILE"; then
|
|
if ! grep -q 'backend: manticore' "$CONFIG_FILE"; then
|
|
sed -i 's/^\([[:space:]]*\)backend:.*/\1backend: manticore/' "$CONFIG_FILE"
|
|
info "Index-Backend auf 'manticore' gesetzt"
|
|
fi
|
|
else
|
|
# backend: Zeile unter index: einfuegen
|
|
sed -i '/^index:/a\ backend: manticore' "$CONFIG_FILE"
|
|
info "Index-Backend 'manticore' hinzugefuegt"
|
|
fi
|
|
# manticore_dsn setzen falls nicht vorhanden
|
|
if ! grep -q 'manticore_dsn' "$CONFIG_FILE"; then
|
|
sed -i '/backend: manticore/a\ manticore_dsn: "manticore@tcp(127.0.0.1:9306)/"' "$CONFIG_FILE"
|
|
info "Manticore-DSN gesetzt"
|
|
fi
|
|
log "Manticore-Konfiguration aktualisiert"
|
|
fi
|
|
|
|
# ── Dateien einspielen ────────────────────────────────────────────────────
|
|
|
|
info "Spiele Backend ein..."
|
|
mkdir -p "$BIN_DIR"
|
|
cp "$BUILD_DIR/archivmail-new" "$BIN_DIR/archivmail"
|
|
chmod +x "$BIN_DIR/archivmail"
|
|
# Service-Binary direkt überschreiben (nach systemctl stop)
|
|
cp "$BIN_DIR/archivmail" "$INSTALL_DIR/archivmail"
|
|
ln -sf "$BIN_DIR/archivmail" /usr/local/bin/archivmail
|
|
log "Backend eingespielt"
|
|
|
|
info "Spiele Cron-Jobs ein..."
|
|
cp "$BUILD_DIR/deploy/cron.d/archivmail" /etc/cron.d/archivmail
|
|
chmod 644 /etc/cron.d/archivmail
|
|
for script in "$BUILD_DIR"/deploy/cron.d/*.sh; do
|
|
cp "$script" "/usr/local/bin/$(basename "$script")"
|
|
chmod 755 "/usr/local/bin/$(basename "$script")"
|
|
done
|
|
log "Cron-Jobs eingespielt (/etc/cron.d/archivmail + Wrapper-Skripte)"
|
|
|
|
info "Spiele Frontend ein (standalone)..."
|
|
# Next.js standalone mirrors the absolute build path — find the dir that contains server.js.
|
|
# The path is typically: .next/standalone/<build-dir>/server.js
|
|
STANDALONE_SERVER=$(find "$BUILD_DIR/.next/standalone" -maxdepth 3 -name "server.js" | head -1)
|
|
[[ -n "$STANDALONE_SERVER" ]] || die "server.js nicht im standalone-Build gefunden"
|
|
STANDALONE_ROOT=$(dirname "$STANDALONE_SERVER")
|
|
# Clean destination and copy fresh standalone output
|
|
rm -rf "$FRONTEND_DIR"
|
|
mkdir -p "$FRONTEND_DIR"
|
|
rsync -a "$STANDALONE_ROOT/" "$FRONTEND_DIR/"
|
|
# Copy static assets from the full build (standalone doesn't include them)
|
|
mkdir -p "$FRONTEND_DIR/.next/static"
|
|
rsync -a --delete "$BUILD_DIR/.next/static/" "$FRONTEND_DIR/.next/static/"
|
|
if [[ -d "$BUILD_DIR/public" ]]; then
|
|
rsync -a "$BUILD_DIR/public/" "$FRONTEND_DIR/public/"
|
|
fi
|
|
log "Frontend eingespielt"
|
|
|
|
# ── systemd Units synchronisieren ─────────────────────────────────────────
|
|
# install.sh schreibt die Unit-Dateien nur beim Erst-Setup. Ohne diesen
|
|
# Schritt bleiben bereits installierte Server auf dem Stand von damals
|
|
# eingefroren, selbst wenn sich die Unit-Definition im Repo ändert (z.B.
|
|
# CAP_NET_ADMIN für die Security-Tab-Firewall-Aktion, nachträglich ergänzt —
|
|
# Server die vor dieser Änderung installiert wurden, hatten die Capability
|
|
# bis zu diesem Fix hier gefehlt). Bei jedem Deploy neu schreiben + reload,
|
|
# damit Unit-Änderungen aus install.sh automatisch nachgezogen werden.
|
|
info "Synchronisiere systemd Units..."
|
|
STORE_DIR="/var/archivmail"
|
|
LOG_DIR="/var/log/archivmail"
|
|
CONFIG_DIR="/etc/archivmail"
|
|
SSL_DIR="/etc/ssl/archivmail"
|
|
AM_USER="archivmail"
|
|
|
|
cat > /etc/systemd/system/archivmail.service << UNIT
|
|
[Unit]
|
|
Description=archivmail Mail Archive Daemon
|
|
After=network.target postgresql.service manticore.service
|
|
Requires=postgresql.service manticore.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=${AM_USER}
|
|
Group=${AM_USER}
|
|
# CAP_NET_ADMIN: required for the admin "enable firewall" action (nft -f /etc/nftables.conf)
|
|
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
|
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
|
|
ExecStart=${INSTALL_DIR}/archivmail --config ${CONFIG_DIR}/config.yml
|
|
ExecReload=/bin/kill -HUP \$MAINPID
|
|
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
|
|
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 synchronisiert"
|
|
|
|
# ── Dienste starten ───────────────────────────────────────────────────────
|
|
|
|
info "Starte Dienste..."
|
|
systemctl start archivmail
|
|
systemctl start archivmail-web
|
|
log "Dienste gestartet"
|
|
|
|
# ── Status prüfen ─────────────────────────────────────────────────────────
|
|
# Hinweis: Kein automatischer Manticore-Reindex mehr bei jedem Update.
|
|
# Neu importierte Mails (IMAP/SMTP/POP3/EML) werden synchron indiziert
|
|
# (siehe internal/imap/importer.go IndexSync) — ein Reindex ist nur nach
|
|
# Schema-Änderungen am Index nötig: manuell mit
|
|
# archivmail reindex --config /etc/archivmail/config.yml
|
|
|
|
BACKEND_OK=0
|
|
FRONTEND_OK=0
|
|
|
|
# Health-Check statt nur systemd-Status: Backend muss tatsächlich auf
|
|
# HTTP antworten (Prozess kann laufen, aber z.B. an DB-Connect hängen).
|
|
info "Prüfe Backend-Health (/api/health)..."
|
|
for i in $(seq 1 15); do
|
|
if systemctl is-active --quiet archivmail && curl -fsS -o /dev/null --max-time 2 http://127.0.0.1:8080/api/health 2>/dev/null; then
|
|
BACKEND_OK=1
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
info "Prüfe Frontend-Health (Port 3000)..."
|
|
for i in $(seq 1 15); do
|
|
if systemctl is-active --quiet archivmail-web && curl -fsS -o /dev/null --max-time 2 http://127.0.0.1:3000/ 2>/dev/null; then
|
|
FRONTEND_OK=1
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
echo ""
|
|
echo " ┌──────────────────────────────────────┐"
|
|
[[ $BACKEND_OK -eq 1 ]] && echo " │ Backend ✓ läuft │" \
|
|
|| echo " │ Backend ✗ nicht aktiv │"
|
|
[[ $FRONTEND_OK -eq 1 ]] && echo " │ Frontend ✓ läuft │" \
|
|
|| echo " │ Frontend ✗ nicht aktiv │"
|
|
echo " └──────────────────────────────────────┘"
|
|
echo ""
|
|
|
|
[[ $BACKEND_OK -eq 1 && $FRONTEND_OK -eq 1 ]] && log "Update abgeschlossen." \
|
|
|| warn "Ein oder mehrere Dienste sind nicht aktiv. Prüfe: journalctl -u archivmail -u archivmail-web"
|