From 25b26038567b58132696a547464788772be448c3 Mon Sep 17 00:00:00 2001 From: Gordon Zimm Date: Wed, 23 Sep 2026 14:47:27 +0200 Subject: [PATCH] ESPO-03-First-Deploy: Erstinbetriebnahme von EspoCRM Richtet EspoCRM auf einer vorbereiteten VM zum ersten Mal ein: Verzeichnisse, Geheimnisse auf der VM erzeugt, config-override.php bereitgelegt, Compose aus dem Stand des Rings gerendert, up -d, Warten auf app-check, Abschlusspruefung. Bricht ab, sobald eine Instanz vorhanden ist (Container, Compose-Datei oder data/config.php). Damit kann dieses Skript keine Migration ohne geprueftes Backup ausloesen - Aktualisierungen bekommen einen eigenen Weg. Die Abschlusspruefung misst zugleich die in ADR 0008 offenen Punkte: Zeichensatz des Servers und Laenge der Record-IDs (36 = UUIDv4 aktiv, sonst Abbruch). Die Datenbankabfragen laufen im Container und lesen das Passwort dort aus der Secret-Datei. Co-Authored-By: Claude Opus 5 --- rmm-tasks/ESPO-03-First-Deploy.sh | 83 +++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100755 rmm-tasks/ESPO-03-First-Deploy.sh diff --git a/rmm-tasks/ESPO-03-First-Deploy.sh b/rmm-tasks/ESPO-03-First-Deploy.sh new file mode 100755 index 0000000..eef384a --- /dev/null +++ b/rmm-tasks/ESPO-03-First-Deploy.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# ESPO-03-First-Deploy - richtet EspoCRM auf einer vorbereiteten VM zum ersten Mal ein. +# Aufruf: ESPO-03-First-Deploy.sh +# Laeuft nur auf einer VM OHNE vorhandene Instanz. Fuer Aktualisierungen ist der Update-Weg zustaendig; +# dieses Skript fasst eine bestehende Instanz nicht an, damit keine Migration ohne geprueftes Backup startet. +set -u + +BASIS_URL=https://gitea.subcura.net/EspoCRM_Public/espo-deploy/raw/branch/main +WARTE_MAX=900 +FQDN="${1:-}" +RING="${2:-}" + +fehler() { echo "FEHLER: $*"; echo "ESPO03_ERGEBNIS: FEHLER"; exit 1; } + +# 1. Vorbedingungen - lieber hier abbrechen als auf halbem Weg. +[ "$(id -u)" -eq 0 ] || fehler "nicht als root gestartet" +command -v docker >/dev/null || fehler "Docker fehlt - erst ESPO-02 ausfuehren" +docker info >/dev/null 2>&1 || fehler "Docker laeuft nicht - erst ESPO-02 pruefen" +[ -n "$FQDN" ] || fehler "kein FQDN uebergeben" +[ -n "$RING" ] || fehler "kein Ring uebergeben" + +# 2. Eine vorhandene Instanz ist der Abbruchgrund dieses Skripts - genau dafuer heisst es First Deploy. +for C in espocrm espocrm-db espocrm-daemon espocrm-websocket; do + docker ps -a --format '{{.Names}}' | grep -qx "$C" && fehler "Container '$C' existiert bereits - hier ist der Update-Weg zustaendig" +done +[ -e /srv/espo/docker-compose.yml ] && fehler "/srv/espo/docker-compose.yml existiert bereits - hier ist der Update-Weg zustaendig" +[ -e /srv/espo/data/config.php ] && fehler "EspoCRM ist bereits installiert (data/config.php) - hier ist der Update-Weg zustaendig" + +# 3. Verzeichnisse anlegen. Die Eigentuemer setzen die Images beim ersten Start selbst. +install -d -m 0755 /srv/espo /srv/espo/bin /srv/espo/mariadb /srv/espo/data /srv/espo/custom /srv/espo/client-custom +install -d -m 0700 /srv/espo/secrets + +# 4. Geheimnisse auf der VM erzeugen - sie stehen in keinem Skript, keiner Ausgabe und keinem Repository. +# Ohne abschliessenden Zeilenumbruch, damit die _FILE-Auswertung der Images genau diesen Wert sieht. +umask 077 +for G in db_root_password db_password; do + [ -s "/srv/espo/secrets/$G" ] && continue + printf '%s' "$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 32)" > "/srv/espo/secrets/$G" + chmod 0600 "/srv/espo/secrets/$G" +done +umask 022 + +# 5. Grundeinstellungen bereitlegen, bevor EspoCRM zum ersten Mal startet. +curl -fsSL "$BASIS_URL/docker/config-override.php" -o /srv/espo/data/config-override.php || fehler "config-override.php nicht abrufbar" + +# 6. Compose aus dem Stand des Rings schreiben. +curl -fsSL "$BASIS_URL/bin/espo-compose-rendern" -o /srv/espo/bin/espo-compose-rendern || fehler "Render-Skript nicht abrufbar" +chmod 0755 /srv/espo/bin/espo-compose-rendern +/srv/espo/bin/espo-compose-rendern "$FQDN" "$RING" || fehler "Compose konnte nicht geschrieben werden" + +# 7. Starten. Die Images werden dabei zum ersten Mal geholt. +docker compose -f /srv/espo/docker-compose.yml up -d || fehler "Start fehlgeschlagen" + +# 8. Auf die Anwendung warten. Der erste Lauf installiert und baut das Schema auf, das dauert. +ENDE=$(( SECONDS + WARTE_MAX )) +while [ "$SECONDS" -lt "$ENDE" ]; do + [ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] && break + sleep 10 +done +[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] \ + || fehler "espocrm nach ${WARTE_MAX}s nicht gesund - 'docker logs espocrm' ansehen" + +# 9. Ergebnis zeigen. Die Datenbankabfragen laufen im Container und lesen das Passwort dort aus der Secret-Datei, +# damit es weder im Skript noch in der Prozessliste der VM auftaucht. +echo "--- Container" +docker compose -f /srv/espo/docker-compose.yml ps --format 'table {{.Name}}\t{{.Status}}' +echo "--- Instanz" +echo "FQDN: $FQDN (Ring $RING)" +echo "Version: $(grep -oP "'version'\s*=>\s*'\K[^']+" /srv/espo/data/config.php 2>/dev/null || echo unbekannt)" +IMAGE="$(docker inspect -f '{{.Config.Image}}' espocrm 2>/dev/null)" +echo "Image: $IMAGE" +echo "Digest: $(docker image inspect --format '{{if .RepoDigests}}{{index .RepoDigests 0}}{{else}}{{.Id}}{{end}}' "$IMAGE" 2>/dev/null)" +DB_ABFRAGE='mariadb -u root -p"$(cat /run/secrets/db_root_password)" -N -B -D espocrm -e' +echo "MariaDB: $(docker exec espocrm-db sh -c "$DB_ABFRAGE \"select version()\"" 2>/dev/null)" +echo "Zeichensatz: $(docker exec espocrm-db sh -c "$DB_ABFRAGE \"select @@character_set_server, @@collation_server\"" 2>/dev/null)" +ID_LAENGE="$(docker exec espocrm-db sh -c "$DB_ABFRAGE \"select length(id) from user limit 1\"" 2>/dev/null)" +echo "ID-Laenge: ${ID_LAENGE:-unbekannt} (36 = UUIDv4 aktiv)" +[ "$ID_LAENGE" = "36" ] || { echo "FEHLER: Record-IDs sind nicht 36 Zeichen lang - recordId.json hat nicht gegriffen"; echo "ESPO03_ERGEBNIS: FEHLER"; exit 1; } + +echo "--- Naechster Schritt von Hand" +echo "Admin-Passwort ('admin') in der Instanz aendern, im Passwort-Safe ablegen," +echo "erst danach DNS-Eintrag und Portfreigabe an der OPNsense setzen." +echo "ESPO03_ERGEBNIS: OK"