S5/S7 AI für Windows:Company Server
Eigenen Company Server fuer den S57AI-Copilot einrichten
Zweck dieser Anleitung
Diese Anleitung beschreibt, wie ein Anwender ohne Zugriff auf das IBHsoftec-Quellprojekt einen eigenen Company Server fuer den S57AI-Copilot einrichtet und betreibt.
Das Kundenpaket enthaelt eine eigenstaendige Python-/FastAPI- Referenzimplementierung. Auf dem Server muss weder S57AI noch ein anderes IBHsoftec-Produkt installiert sein.
Das Paket kann wahlweise als nativer systemd-Dienst oder als
nicht privilegierter Docker-Container betrieben werden.
Download: S57AI Company Server Kundenpaket herunterladen
Was ist ein Company Server?
Der Company Server ist ein kontrolliertes Gateway zwischen den S57AI-Arbeitsplaetzen und einem KI-Dienst.
S57AI-Copilot
|
| HTTPS und Rechner-Fingerprint
v
Company Server
|
| zentral verwalteter API-Key
v
Ollama, Open WebUI, vLLM, LiteLLM, OpenAI oder anderer LLM-Dienst
Der Company Server fuehrt das Sprachmodell normalerweise nicht selbst aus. Er leitet freigegebene Anfragen an einen vorhandenen LLM-Dienst weiter. Der LLM-Dienst kann auf demselben Linux-Rechner, im Firmennetz oder bei einem Cloud-Anbieter laufen.
Funktionen und Aufgaben
Zentrale Verwaltung des KI-Zugangs
- Der Upstream-API-Key wird nur auf dem Company Server gespeichert.
- Auf den S57AI-Arbeitsplaetzen wird lediglich die URL des Company Servers eingetragen.
- Ein ausgetauschter Upstream-Key muss nur einmal auf dem Server geaendert werden.
- Der eigentliche LLM-Dienst muss nicht direkt aus dem Arbeitsplatznetz erreichbar sein.
Einheitliche Schnittstelle fuer S57AI
Der Server stellt dem Copilot unabhaengig vom verwendeten LLM mindestens diese Endpunkte bereit:
GET /health- einfache FunktionskontrolleGET /v1/models- verfuegbare ModellePOST /v1/copilot/chat- Textanfragen
Damit kann der dahinterliegende Anbieter gewechselt werden, ohne alle Arbeitsplaetze neu zu programmieren.
Modellvorgabe und Modellauswahl
Der Company Server kann:
- die Modellliste des Upstream-Dienstes durchreichen;
- bei nicht verfuegbarer Modellliste ein konfiguriertes Standardmodell melden;
- die effektive Kontextgroesse des Standardmodells an S57AI melden;
- bei einer Anfrage ohne Modell das serverseitige Standardmodell verwenden.
Das Modellfeld im S57AI-Copilot enthaelt dadurch nur Modelle, die der Company Server bereitstellt.
Zugriffskontrolle
S57AI uebermittelt den Rechner-Fingerprint:
- bei
GET /v1/modelsim HeaderX-S57AI-Fingerprint; - bei
POST /v1/copilot/chatim Feldmachine_fingerprint.
Ueber ALLOWED_FINGERPRINTS legt der Administrator fest, welche
Rechner den Company Server verwenden duerfen.
Schutz und Entkopplung
- Der API-Key des LLM-Dienstes bleibt vor den Clients verborgen.
- nginx uebernimmt HTTPS und die externe Netzwerkverbindung.
- Der Python-Dienst lauscht nur lokal auf
127.0.0.1:5100. - Zeitueberschreitungen und Upstream-Fehler werden kontrolliert an den Client zurueckgegeben.
Grenzen der Referenzimplementierung
Das einfache Kundenpaket unterstuetzt Text-Chat und Modelllisten. Es enthaelt keine grafische Administration, Mandantenverwaltung, Abrechnung, Dateianhaenge, Spracherkennung oder Sprachausgabe.
Voraussetzungen
Empfohlen werden:
- Ubuntu Server oder Debian;
- mindestens 1 CPU-Kern und 1 GB RAM fuer den Gateway-Dienst;
- feste IP-Adresse oder DNS-Name;
- Netzwerkzugriff vom Company Server zum LLM-Dienst;
- Netzwerkzugriff der S57AI-Arbeitsplaetze zum Company Server;
- Benutzer mit
sudo-Rechten; - fuer produktiven externen Zugriff ein TLS-Zertifikat.
Die Hardware fuer das eigentliche LLM kommt zusaetzlich hinzu. Ein lokal ausgefuehrtes grosses Modell benoetigt je nach Modell ausreichend RAM oder GPU-Speicher.
Inhalt des Kundenpakets
Nach dem Entpacken sind mindestens diese Dateien vorhanden:
server.py requirements.txt company-server.env.example s57ai-customer-company-server.service Dockerfile .dockerignore README.md COMPANY-SERVER-ANLEITUNG.md
| Datei | Aufgabe |
|---|---|
server.py
|
Company-Server-Referenzimplementierung |
requirements.txt
|
Benoetigte Python-Pakete |
company-server.env.example
|
Beispiel fuer die geschuetzte Serverkonfiguration |
s57ai-customer-company-server.service
|
systemd-Dienstdefinition |
Dockerfile
|
Definition des nicht privilegierten Container-Images mit Healthcheck |
.dockerignore
|
Schliesst lokale und vertrauliche Dateien vom Image-Build aus |
README.md
|
Kurzanleitung im Paket |
COMPANY-SERVER-ANLEITUNG.md
|
Ausfuehrliche Anleitung als Markdown |
Kundenpaket uebertragen
Das ZIP-Paket auf den Linux-Rechner kopieren und nach
/opt/s57ai-company-server entpacken:
sudo apt update sudo apt install -y unzip sudo mkdir -p /opt/s57ai-company-server sudo unzip S57AI-Company-Server-Kundenpaket.zip \ -d /opt/s57ai-company-server
Alternative Installation mit Docker
Image bauen
Im entpackten Verzeichnis:
docker build -t s57ai-company-server:1.0 .
Das Image verwendet Python 3.12, fuehrt den Dienst unter einem nicht
privilegierten Benutzer mit UID/GID 10001 aus und enthaelt einen
Docker-Healthcheck fuer /health.
Konfiguration bereitstellen
sudo cp company-server.env.example /etc/s57ai-company-server.env sudo chmod 600 /etc/s57ai-company-server.env sudo nano /etc/s57ai-company-server.env
Innerhalb eines Containers bezeichnet 127.0.0.1 den Container
selbst. Wenn Ollama oder Open WebUI auf dem Linux-Docker-Host laeuft, muss
deshalb host.docker.internal verwendet werden.
Ollama auf dem Docker-Host:
UPSTREAM_BASE_URL=http://host.docker.internal:11434
Open WebUI auf dem Docker-Host:
UPSTREAM_BASE_URL=http://host.docker.internal:3000 UPSTREAM_MODELS_URL=http://host.docker.internal:3000/api/models UPSTREAM_CHAT_URL=http://host.docker.internal:3000/api/chat/completions
Laufen Company Server und LLM im selben benutzerdefinierten Docker-Netzwerk,
wird stattdessen der Container- oder Servicename verwendet, beispielsweise
http://ollama:11434.
Container starten
docker run -d \ --name s57ai-company-server \ --restart unless-stopped \ --env-file /etc/s57ai-company-server.env \ --add-host host.docker.internal:host-gateway \ -p 127.0.0.1:5100:5100 \ s57ai-company-server:1.0
Die Bindung an 127.0.0.1 verhindert einen direkten oeffentlichen
Zugriff auf Port 5100. nginx stellt anschliessend HTTPS bereit.
Container pruefen
docker ps
docker inspect --format '{{json .State.Health}}' \
s57ai-company-server
docker logs s57ai-company-server
curl http://127.0.0.1:5100/health
Container aktualisieren
docker build -t s57ai-company-server:1.1 . docker stop s57ai-company-server docker rm s57ai-company-server
Anschliessend wird der Startbefehl mit dem neuen Image-Tag wiederholt. Die
Konfiguration bleibt ausserhalb des Containers in
/etc/s57ai-company-server.env erhalten.
Native Installation als systemd-Dienst
Systempakete und Dienstbenutzer
sudo apt update sudo apt install -y python3 python3-venv nginx curl sudo useradd --system \ --home /opt/s57ai-company-server \ --shell /usr/sbin/nologin \ s57ai-company sudo chown -R s57ai-company:s57ai-company \ /opt/s57ai-company-server
Falls der Benutzer bereits vorhanden ist, kann die entsprechende Meldung ignoriert werden.
Python-Umgebung
cd /opt/s57ai-company-server sudo -u s57ai-company python3 -m venv venv sudo -u s57ai-company ./venv/bin/pip install --upgrade pip sudo -u s57ai-company ./venv/bin/pip install -r requirements.txt
Konfiguration und systemd
sudo cp company-server.env.example \ /etc/s57ai-company-server.env sudo chown root:root /etc/s57ai-company-server.env sudo chmod 600 /etc/s57ai-company-server.env sudo cp s57ai-customer-company-server.service \ /etc/systemd/system/s57ai-customer-company-server.service
LLM-Dienst konfigurieren
Die Konfigurationsdatei wird mit folgendem Befehl geoeffnet:
sudo nano /etc/s57ai-company-server.env
Einstellungen
| Einstellung | Aufgabe |
|---|---|
UPSTREAM_BASE_URL
|
Basisadresse eines OpenAI-kompatiblen Dienstes |
UPSTREAM_MODELS_URL
|
Optionaler vollstaendiger Endpunkt fuer die Modellliste |
UPSTREAM_CHAT_URL
|
Optionaler vollstaendiger Endpunkt fuer Chat |
UPSTREAM_API_KEY
|
API-Key des LLM-Dienstes |
DEFAULT_MODEL
|
Ersatz und serverseitige Vorgabe, falls keine Modellliste verfuegbar ist |
DEFAULT_CONTEXT_LENGTH
|
Effektive Kontextgroesse des Standardmodells in Tokens; 0 bedeutet unbekannt
|
UPSTREAM_TIMEOUT
|
Maximale Wartezeit auf eine Modellantwort in Sekunden |
ALLOWED_FINGERPRINTS
|
Zugelassene S57AI-Rechner, durch Komma getrennt |
Wenn UPSTREAM_MODELS_URL und UPSTREAM_CHAT_URL nicht
gesetzt sind, verwendet der Server:
<UPSTREAM_BASE_URL>/v1/models <UPSTREAM_BASE_URL>/v1/chat/completions
Direktes Ollama
UPSTREAM_BASE_URL=http://127.0.0.1:11434 UPSTREAM_API_KEY=ollama DEFAULT_MODEL=deepseek-r1:latest DEFAULT_CONTEXT_LENGTH=8192 UPSTREAM_TIMEOUT=300 ALLOWED_FINGERPRINTS=
Vorher pruefen:
ollama list curl http://127.0.0.1:11434/v1/models
Der Wert von DEFAULT_MODEL muss exakt einem installierten Modell
entsprechen.
Open WebUI
Open WebUI verwendet fuer die hier benoetigten Funktionen typischerweise die
Pfade /api/models und /api/chat/completions:
UPSTREAM_BASE_URL=http://127.0.0.1:3000 UPSTREAM_MODELS_URL=http://127.0.0.1:3000/api/models UPSTREAM_CHAT_URL=http://127.0.0.1:3000/api/chat/completions UPSTREAM_API_KEY=HIER_DEN_OPEN_WEBUI_API_KEY_EINTRAGEN DEFAULT_MODEL=deepseek-coder-v2:16b DEFAULT_CONTEXT_LENGTH=8192 UPSTREAM_TIMEOUT=300 ALLOWED_FINGERPRINTS=
Der Open-WebUI-API-Key wird in Open WebUI fuer einen technischen Benutzer erzeugt. Er darf nicht an S57AI-Anwender verteilt werden.
curl -H "Authorization: Bearer HIER_DEN_API_KEY_EINTRAGEN" \ http://127.0.0.1:3000/api/models
OpenAI
UPSTREAM_BASE_URL=https://api.openai.com UPSTREAM_API_KEY=HIER_DEN_OPENAI_API_KEY_EINTRAGEN DEFAULT_MODEL=EIN_FREIGESCHALTETES_MODELL DEFAULT_CONTEXT_LENGTH=0 UPSTREAM_TIMEOUT=300 ALLOWED_FINGERPRINTS=
Der konkrete Modellname muss fuer das verwendete OpenAI-Projekt freigeschaltet sein. Ein frei erfundener oder nicht verfuegbarer Modellname fuehrt zu einer Fehlermeldung.
vLLM, LiteLLM und andere kompatible Server
Wenn der Dienst eine vollstaendige OpenAI-kompatible /v1-API
bereitstellt:
UPSTREAM_BASE_URL=https://llm.intern.example UPSTREAM_API_KEY=GEHEIMER_API_KEY DEFAULT_MODEL=modellname-des-anbieters DEFAULT_CONTEXT_LENGTH=32768 UPSTREAM_TIMEOUT=300 ALLOWED_FINGERPRINTS=
Bei abweichenden Pfaden werden UPSTREAM_MODELS_URL und
UPSTREAM_CHAT_URL ausdruecklich gesetzt.
Rechner freigeben
Der Fingerprint wird im S57AI-Copilot beim Provider
Company Server maskiert angezeigt und kann kopiert werden.
Mehrere Rechner werden durch Komma getrennt:
ALLOWED_FINGERPRINTS=8B4F...F03A,4A21...91C0
Ein leerer Wert erlaubt alle Rechner:
ALLOWED_FINGERPRINTS=
Das ist fuer einen ersten Test geeignet, sollte aber produktiv nicht dauerhaft verwendet werden.
Nach einer Aenderung:
sudo systemctl restart s57ai-customer-company-server
Dienst starten und lokal testen
sudo systemctl daemon-reload sudo systemctl enable --now s57ai-customer-company-server sudo systemctl status s57ai-customer-company-server --no-pager
Der Dienst lauscht absichtlich nur lokal:
ss -ltnp | grep ':5100'
Gesundheitspruefung:
curl http://127.0.0.1:5100/health
Erwartete Antwort:
{"status":"ok"}
Modellliste:
curl -H "X-S57AI-Fingerprint: FREIGEGEBENER_FINGERPRINT" \ http://127.0.0.1:5100/v1/models
Beispielantwort:
{
"object": "list",
"data": [
{
"id": "deepseek-r1:latest",
"object": "model",
"owned_by": "customer-company-server",
"context_length": 8192
}
]
}
Chat testen:
curl -X POST http://127.0.0.1:5100/v1/copilot/chat \
-H "Content-Type: application/json" \
-d '{
"machine_fingerprint": "FREIGEGEBENER_FINGERPRINT",
"model": "",
"messages": [
{"role": "user", "content": "Antworte nur mit OK."}
]
}'
Ein leerer Modellname bewirkt, dass DEFAULT_MODEL verwendet wird.
HTTPS mit nginx
Datei /etc/nginx/sites-available/s57ai-company-server erstellen:
server {
listen 80;
server_name ai.example.com;
client_max_body_size 10m;
location / {
proxy_pass http://127.0.0.1:5100;
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;
proxy_read_timeout 360s;
proxy_send_timeout 360s;
}
}
Aktivieren:
sudo ln -s /etc/nginx/sites-available/s57ai-company-server \ /etc/nginx/sites-enabled/s57ai-company-server sudo nginx -t sudo systemctl reload nginx
TLS mit Let's Encrypt:
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d ai.example.com
Abschliessend:
curl https://ai.example.com/health curl -H "X-S57AI-Fingerprint: FREIGEGEBENER_FINGERPRINT" \ https://ai.example.com/v1/models
Bei rein internem Betrieb kann ein Zertifikat der Unternehmens-PKI verwendet werden. Das ausstellende Stammzertifikat muss auf den S57AI-Arbeitsplaetzen als vertrauenswuerdig installiert sein.
Firewall
Nach aussen wird nur HTTPS benoetigt:
sudo ufw allow OpenSSH sudo ufw allow 443/tcp sudo ufw enable
Port 5100 darf nicht oeffentlich geoeffnet werden. Auch
Ollama-Port 11434 und Open-WebUI-Port 3000 sollten
nur aus den tatsaechlich benoetigten Netzen erreichbar sein.
S57AI-Copilot konfigurieren
Im KI-Copilot:
Provider: Company Server Server-URL: https://ai.example.com
- Provider
Company Serverauswaehlen. - Server-URL eintragen.
- Modellauswahl oeffnen.
- Pruefen, ob die vom Server gemeldeten Modelle erscheinen.
- Eine kurze Anfrage senden.
Der Upstream-API-Key wird nicht im S57AI-Copilot eingetragen.
Sicherheitsempfehlungen
- Produktiv ausschliesslich HTTPS verwenden.
- Upstream-API-Keys nur in
/etc/s57ai-company-server.envspeichern. - Die Konfigurationsdatei mit Dateirecht
600schuetzen. - Den Python-Dienst nur an
127.0.0.1binden. - Nur benoetigte Rechner-Fingerprints freigeben.
- Einen technischen Upstream-Benutzer mit begrenztem Budget verwenden.
- Token-, Kosten- und Rate-Limits beim Upstream konfigurieren.
- Betriebssystem und Python-Abhaengigkeiten regelmaessig aktualisieren.
- Keine Projektdaten oder vollstaendigen KI-Anfragen in allgemein zugaengliche Logs schreiben.
- API-Keys niemals in ein unverschluesseltes Backup oder Quellcode-Repository aufnehmen.
Der Rechner-Fingerprint ist eine zusaetzliche Freigabekontrolle. Er ersetzt nicht HTTPS, Firewallregeln und eine sichere Netzwerkarchitektur.
Betrieb und Wartung
Status:
sudo systemctl status s57ai-customer-company-server --no-pager
Live-Protokoll:
sudo journalctl -u s57ai-customer-company-server -f
Letzte Meldungen:
sudo journalctl -u s57ai-customer-company-server \ -n 200 --no-pager
Neustart:
sudo systemctl restart s57ai-customer-company-server
Aktualisierung
Vor einer Aktualisierung:
sudo cp /etc/s57ai-company-server.env \ /root/s57ai-company-server.env.backup
Neue Paketdateien nach /opt/s57ai-company-server kopieren:
cd /opt/s57ai-company-server sudo chown -R s57ai-company:s57ai-company . sudo -u s57ai-company ./venv/bin/pip install -r requirements.txt sudo systemctl restart s57ai-customer-company-server
Danach /health, /v1/models und eine Chat-Anfrage
testen.
Fehlerdiagnose
Modellliste nicht erreichbar
curl -v http://127.0.0.1:5100/v1/models sudo journalctl -u s57ai-customer-company-server \ -n 200 --no-pager
Pruefen:
- Laeuft der Company Server?
- Stimmt die Server-URL im Copilot?
- Erlauben Firewall und nginx den Zugriff?
- Ist der Fingerprint freigegeben?
The model ... does not exist or you do not have access to it
DEFAULT_MODEL oder das ausgewaehlte Modell ist beim Upstream nicht
vorhanden. Den Modellnamen exakt aus der Modellliste des Upstreams uebernehmen.
HTTP 401 oder 403
- Upstream-API-Key ungueltig;
- Rechner-Fingerprint nicht freigegeben;
- Zugriff beim Cloud-Anbieter nicht erlaubt.
HTTP 404
Meist ist der konfigurierte Pfad falsch. Bei Open WebUI insbesondere
UPSTREAM_MODELS_URL und UPSTREAM_CHAT_URL pruefen.
HTTP 502
Der Company Server laeuft, erreicht aber den Upstream nicht oder erhaelt von ihm eine ungueltige Antwort.
Zeitueberschreitung
UPSTREAM_TIMEOUTerhoehen;- Auslastung und Arbeitsspeicher des LLM-Rechners pruefen;
- kleineres Modell verwenden;
- Netzwerkverbindung untersuchen.
Kontextgroesse wird nicht angezeigt
Der Upstream meldet keine context_length. Die tatsaechlich
konfigurierte Kontextgroesse in DEFAULT_CONTEXT_LENGTH eintragen
und den Dienst neu starten.
API-Vertrag fuer eigene Implementierungen
Ein selbst entwickelter Company Server kann in jeder Programmiersprache geschrieben werden. Entscheidend ist der API-Vertrag.
Modellliste
GET /v1/models X-S57AI-Fingerprint: <Fingerprint>
Antwort:
{
"object": "list",
"data": [
{
"id": "modell-id",
"object": "model",
"owned_by": "company-server",
"context_length": 8192
}
]
}
Chat
POST /v1/copilot/chat Content-Type: application/json
Anfrage:
{
"machine_fingerprint": "ABC123",
"app_version": "1.0",
"language": "de",
"model": "modell-id",
"stream": false,
"messages": [
{"role": "system", "content": "Systemanweisung"},
{"role": "user", "content": "Benutzerfrage"}
]
}
Antwort:
{
"reply": "Antwort des Modells"
}
Der Server muss Eingaben validieren, unbekannte Rechner ablehnen, Zeitlimits setzen und Upstream-Fehler ohne Preisgabe von API-Keys zurueckgeben.
Abnahmekriterien
Die Installation ist betriebsbereit, wenn:
systemctl statusden Zustandactive (running)meldet;GET /healtherfolgreich antwortet;GET /v1/modelsmindestens ein gueltiges Modell liefert;- die Kontextgroesse korrekt gemeldet oder bewusst als unbekannt behandelt wird;
- ein freigegebener S57AI-Rechner chatten kann;
- ein nicht freigegebener Fingerprint mit HTTP 403 abgewiesen wird;
- der Upstream-API-Key auf keinem Client gespeichert ist;
- der externe Zugriff ausschliesslich ueber HTTPS erfolgt.
Wiki-Hinweis fuer Administratoren
Damit der Downloadlink am Anfang dieser Seite funktioniert, muss die Datei
S57AI-Company-Server-Kundenpaket.zip ueber die
MediaWiki-Spezialseite Spezial:Hochladen unter genau diesem
Dateinamen in das Wiki geladen werden.