- tools/ki-proxy: setzt API-Schlüssel aus der Windows-Anmeldeinformationsverwaltung ein, nur im Speicher, ohne Header-Protokoll; Tests gegen Platzhalter-Server - docs/server-anforderungen.md für den ITM-Entwickler - .gitleaks.toml erkennt zki_/zodl_/zocr_-Schlüssel - CLAUDE.md, Plan, Tech-Stack: Schlüssel nie in .env, in der App verschlüsselt in der DB Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.9 KiB
KI-BauIN – Server-Anforderungen (Staging und Produktion)
Stand: 5. Oktober 2026. Für den ITM-Entwickler, der die Server aufbaut. Hintergründe stehen in
docs/tech-stack.md, Termine in docs/projektplan.md.
Überblick
- Zwei Umgebungen, gleich aufgebaut: Staging (Pilot mit BauIn, ab KW 44) und Produktion (ab KW 51). Getrennte Server, getrennte Datenbanken, getrennte API-Schlüssel.
- Ein Server je Umgebung reicht: Anwendung, MySQL, Meilisearch und Worker laufen auf derselben VM.
- Betrieb nativ, ohne Docker: Nginx, PHP-FPM, Worker unter systemd, Cron für den Scheduler.
- Die Versionen entsprechen der Entwicklung. Abweichungen bitte vorher abstimmen.
Ausstattung je Server (Vorschlag)
| Vorschlag | Anmerkung | |
|---|---|---|
| Betriebssystem | Ubuntu Server 24.04 LTS | Debian 12/13 geht auch |
| CPU | 4 vCPU | |
| RAM | 16 GB | Meilisearch hält Vektoren mit 4.096 Dimensionen; endgültig nach dem Meilisearch-Test (KW 41) |
| Platte | 150 GB SSD, erweiterbar | Daten (MySQL, Uploads, Meilisearch) am besten auf eigenem Volume |
| Verschlüsselung | Festplattenverschlüsselung gewünscht | Entscheidung mit BauIn offen |
| Zeitzone | Europe/Berlin, NTP aktiv |
Software
| Paket | Version | Hinweise |
|---|---|---|
| PHP (FPM und CLI) | 8.5 | Erweiterungen: bcmath, ctype, curl, dom, fileinfo, gd, iconv, intl, mbstring, opcache, openssl, pcntl, pdo_mysql, simplexml, sodium, tokenizer, xml, xmlreader, xmlwriter, zip, zlib |
| Composer | 2.x | |
| Node.js mit npm | 22 LTS | nur zum Bauen der Oberfläche beim Deployment |
| MySQL | 8.4 LTS | utf8mb4 / utf8mb4_unicode_ci, nur auf 127.0.0.1, max_allowed_packet mindestens 64M |
| Meilisearch | v1.54.2 (fest) | eigener systemd-Dienst, nur auf 127.0.0.1:7700, Master-Key gesetzt, --no-analytics |
| Nginx | aktuelle Version der Distribution | client_max_body_size 200M (ZIP mit LVs), HTTP → HTTPS |
| poppler-utils, qpdf | Distribution | Text und Seitenzahlen aus PDFs lesen, große PDFs teilen (Grenze der KI-API: 50 MB) |
| git, unzip | Distribution | Deployment aus Gitea |
Dienste
php8.5-fpm: Pool läuft unter einem eigenen Benutzer (Vorschlagkibauin).nginxmysqlmeilisearch: eigener Benutzer, Daten auf dem Datenvolume.- Worker: zwei Instanzen
php artisan queue:work database --sleep=3 --tries=3 --max-time=3600unter systemd, Benutzerkibauin, mit automatischem Neustart. - Scheduler: Cron-Zeile
* * * * * cd /srv/ki-bauin/current && php artisan schedule:run.
Die Vorlagen für den Nginx-Server-Block, die systemd-Units, die Cron-Zeile, das Deploy-Skript und
das Backup-Skript liefern wir bis KW 44 im Repository (deploy/).
Netzwerk
-
Eingehend: nur 443 sowie 80 für die Weiterleitung und die Zertifikatsausstellung. SSH nur mit Schlüssel und möglichst nur über VPN oder freigegebene IP-Adressen.
-
Zugriff für BauIn: offen, ob aus dem Internet mit Login und 2FA oder nur über VPN bzw. freigegebene IP-Adressen (Fragenkatalog B2).
-
Ausgehend:
https://api-werk.de(KI-API)- der Gitea von ITM (Deployment)
- SMTP für Benachrichtigungen
- Paketquellen für Updates
Die Anwendung selbst lädt nichts von fremden Servern.
-
MySQL und Meilisearch sind nur lokal erreichbar.
Verzeichnisse
/srv/ki-bauin/
├── releases/<zeitstempel>/ je Deployment ein Verzeichnis
├── current -> releases/… aktive Version (Symlink)
└── shared/
├── .env Rechte 0600, Besitzer kibauin
└── storage/ u. a. storage/app/private = Uploads (nie über Nginx ausliefern)
Konfiguration und Geheimnisse
- In
shared/.envstehenAPP_KEY, das Datenbank-Passwort, der Meilisearch-Master-Key und die Mail-Zugangsdaten. - Die Schlüssel der KI-API stehen nicht in der
.env. Sie werden in der Anwendung unter Verwaltung → Einstellungen eingetragen und verschlüsselt in der Datenbank gespeichert. Danach sind sie nur noch beschreibbar, nicht mehr lesbar. - Der
APP_KEYmuss zusätzlich sicher außerhalb des Servers aufbewahrt werden, z. B. im Passwortmanager. Ohne ihn lassen sich verschlüsselte Felder aus einem Backup nicht wiederherstellen.
Backups (Vorschlag, Entscheidung mit BauIn offen)
- Was: täglich
mysqldump --single-transaction, dazushared/storage/app/privateundshared/.env. - Wie: vor dem Verlassen des Servers verschlüsseln (z. B. restic), Ziel außerhalb des Servers.
- Aufbewahrung: z. B. 7 tägliche, 4 wöchentliche, 6 monatliche Stände.
- Meilisearch wird nicht gesichert, der Index wird aus MySQL neu aufgebaut.
- Restore-Test: einmal vollständig vor dem Produktivstart (KW 3/2027).
Überwachung
- Lebenszeichen:
https://<domain>/upantwortet mit HTTP 200. - Worker und Scheduler melden Lebenszeichen, fehlgeschlagene Jobs werden gezählt. Die Artisan-Befehle dafür liefern wir.
- Alarm per Mail, wenn die Anwendung, ein Worker oder der Scheduler ausfällt, wenn die Platte zu über 80 % voll ist oder wenn die KI-API nicht erreichbar ist.
Deployment
Ablauf, als Skript geliefert:
- Code aus dem Gitea holen.
composer install --no-dev --optimize-autoloadernpm ci && npm run buildphp artisan migrate --force- Konfiguration, Routen und Views cachen.
php artisan queue:restart- PHP-FPM neu laden.
Wer im Betrieb deployt und Updates einspielt, ist noch offen (Fragenkatalog C12).
Termine
| Bis | Was |
|---|---|
| KW 43 | Staging-Server mit SSH-Zugang und Grundinstallation |
| KW 44 | Staging fertig: Domain, Zertifikat, Dienste, erstes Deployment |
| KW 51 | Produktionsserver fertig |
| KW 3/2027 | Backups und Alarmierung in Produktion, Restore-Test |
Offen
- Standort und Rechenzentrum der Server, Festplattenverschlüsselung
- Domain(s) und Zertifikat (Let's Encrypt oder eigenes)
- Ziel und Zuständigkeit der Backups
- Zugriff für BauIn: Internet oder VPN
- SMTP-Server und Absenderadresse