ip·Solis -- Produktions-Deployment-Leitfaden
Diese Anleitung führt durch die Einrichtung der ip·Solis-Plattform auf einem neuen On-Premises-Server. Vorkenntnisse des Quellcodes sind nicht erforderlich.
Inhaltsverzeichnis
- Voraussetzungen
- Software beziehen
- Umgebungsvariablen konfigurieren
- SSL / TLS-Zertifikat einrichten
- Produktions-Compose-Overlay erstellen
- Stack starten
- Ersteinrichtung Administrator
- Entra ID SSO (Portal-Authentifizierung)
- Deployment überprüfen
- Backup & Wartung
- Update auf neue Version
- Hochverfügbarkeit
- Fehlerbehebung
- Sauberer Neustart (Testumgebungen)
1. Voraussetzungen
Serveranforderungen
| Komponente | Minimum | Empfohlen |
|---|---|---|
| Betriebssystem | Linux (Debian/Ubuntu empfohlen) | Ubuntu 22.04 LTS oder neuer |
| CPU | 2 Kerne | 4 Kerne |
| RAM | 4 GB | 8 GB |
| Festplatte | 20 GB | 50 GB (abhängig von der Anzahl verwalteter Assets) |
Software
Vor der Installation folgendes einrichten:
- Docker Engine >= 24.0 -- Docker installieren
- Docker Compose >= 2.20 (im Docker Engine-Paket enthalten)
- Git -- zum Klonen des Repositorys
Nach der Docker-Installation den Deployment-User der docker-Gruppe hinzufügen,
damit docker compose-Befehle ohne sudo ausgeführt werden können:
sudo usermod -aG docker $USER
# Anschließend ab- und wieder anmelden (oder: newgrp docker)
Installation überprüfen:
docker --version # Docker version 24.x oder höher
docker compose version # Docker Compose version v2.20 oder höher
git --version
Netzwerkanforderungen
Der Server benötigt ausgehenden Zugriff auf:
| Ziel | Zweck |
|---|---|
| Active Directory / LDAP-Server (Port 389 oder 636) | Benutzervalidierung, Vorgesetztensuche, Gruppenmitgliedschaft |
| SMTP-Relay | E-Mail-Benachrichtigungen |
| vSphere / XenServer (falls verwendet) | VM-Lifecycle-Automatisierung |
| SCCM-Server (falls verwendet) | Tasksequenz-Trigger |
Eingehend: Die Ports 80 und 443 müssen von den Browsern der Nutzer erreichbar sein.
2. Software beziehen
Frische Umgebung empfohlen: Docker-Volumes (Datenbankdaten) überleben ein
rm -rf /opt/ipsolis— sie liegen unter/var/lib/docker/volumes/und bleiben erhalten, bis sie explizit gelöscht werden. Für eine saubere Erstinstallation sicherstellen, dass keine alten Volumes vorhanden sind. Anleitung: Sauberer Neustart (Testumgebungen).
Repository klonen und Images beziehen — keine Authentifizierung erforderlich:
cd /opt
sudo git clone https://github.com/XenPool/ipsolis.git ipsolis
cd ipsolis
Die Docker-Images (ghcr.io/xenpool/ipsolis-api und ghcr.io/xenpool/ipsolis-worker) sind öffentlich und werden beim Start des Stacks automatisch heruntergeladen.
Lizenzierung: ip·Solis ist für nicht-kommerzielle Nutzung und Evaluierung kostenlos. Für kommerzielle Nutzung ist eine Lizenz erforderlich — siehe LICENSE und Kontakt sales@xenpool.de für den Kauf.
3. Umgebungsvariablen konfigurieren
Beispieldatei kopieren und bearbeiten:
sudo cp .env.example .env
sudo nano .env
Pflichtfelder
# Sichere Datenbankzugangsdaten
POSTGRES_PASSWORD=<sicheres-passwort-generieren>
# Sichere API-Secrets -- zufällige Zeichenketten mit mindestens 32 Zeichen
API_SECRET_KEY=<zufallszeichenkette-min-32-zeichen>
WEBHOOK_SECRET_TOKEN=<zufallszeichenkette>
ADMIN_API_KEY=<zufallszeichenkette-min-32-zeichen>
# CORS -- auf die Produktionsdomain setzen ← YOUR_HOSTNAME.YOUR_COMPANY.COM ersetzen
CORS_ORIGINS=https://YOUR_HOSTNAME.YOUR_COMPANY.COM
FLOWER_PASSWORD=<sicheres-passwort>
Tipp: Sichere Passwörter generieren mit:
openssl rand -base64 32
4. SSL / TLS-Zertifikat einrichten
Die Plattform läuft hinter einem nginx-Reverse-Proxy, der SSL terminiert. Ein TLS-Zertifikat und ein privater Schlüssel werden benötigt.
Option A: Internes / selbst-signiertes Zertifikat (Intranet)
Wenn der Server nur im Unternehmensnetzwerk erreichbar ist, mkcert für ein vertrauenswürdiges Zertifikat verwenden:
# mkcert installieren (einmalig)
# Ubuntu/Debian:
sudo apt install -y libnss3-tools
sudo curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"
sudo chmod +x mkcert-v*-linux-amd64
sudo mv mkcert-v*-linux-amd64 /usr/local/bin/mkcert
# Lokale CA in den System-Trust-Store installieren
sudo mkcert -install
# Zertifikat für den Hostnamen generieren ← YOUR_HOSTNAME.YOUR_COMPANY.COM ersetzen
sudo mkdir -p nginx/ssl
sudo mkcert -cert-file nginx/ssl/cert.pem -key-file nginx/ssl/key.pem YOUR_HOSTNAME.YOUR_COMPANY.COM
Wichtig: Damit Browser auf anderen Rechnern diesem Zertifikat vertrauen, muss die Root-CA (
mkcert -CAROOTzeigt den Pfad) via Gruppenrichtlinie oder den unternehmensinternen CA-Trust-Store auf die Client-Rechner verteilt werden.
Stammzertifikat auf Windows-Client installieren:
# Auf dem Server — Stammzertifikat für den Download bereitstellen
sudo cp $(sudo mkcert -CAROOT)/rootCA.pem /tmp/ipsolis-rootCA.pem
sudo chmod 644 /tmp/ipsolis-rootCA.pem
Datei auf den Windows-Laptop kopieren (SCP, USB o. ä.), dann:
Option 1 — per Doppelklick:
- Datei in
ipsolis-rootCA.crtumbenennen - Doppelklick → Zertifikat installieren
- Lokaler Computer → Vertrauenswürdige Stammzertifizierungsstellen
- Browser neu starten
Option 2 — per PowerShell (als Administrator):
certutil -addstore -f "ROOT" ipsolis-rootCA.crt
Nach der Installation vertrauen Chrome, Edge und Firefox (mit Windows-Trust-Store) dem Zertifikat ohne Warnung.
Option B: Zertifikat der internen CA (Empfohlen für Produktion)
Wenn die Organisation eine interne Zertifizierungsstelle betreibt (z. B. Active Directory Certificate Services):
- CSR auf dem Server erzeugen: (YOUR_HOSTNAME.YOUR_COMPANY.COM ersetzen)
sudo mkdir -p nginx/ssl sudo openssl req -new -newkey rsa:2048 -nodes \ -keyout nginx/ssl/key.pem \ -out nginx/ssl/server.csr \ -subj "/CN=YOUR_HOSTNAME.YOUR_COMPANY.COM" nginx/ssl/server.csrbei der CA einreichen und das signierte Zertifikat erhalten.- Das signierte Zertifikat als
nginx/ssl/cert.pemspeichern. - Falls die CA ein Zwischen-/Kettenzertifikat liefert, an
cert.pemanhängen:cat signiertes-zertifikat.pem zwischen-ca.pem | sudo tee nginx/ssl/cert.pem > /dev/null
Option C: Let's Encrypt (öffentlich erreichbare Server)
Wenn der Server öffentlich zugänglich ist, können kostenlose Zertifikate von Let's Encrypt genutzt werden:
sudo apt install -y certbot
sudo certbot certonly --standalone -d YOUR_HOSTNAME.YOUR_COMPANY.COM # ← ersetzen
# Symlinks in das ssl-Verzeichnis
sudo mkdir -p nginx/ssl
sudo ln -sf /etc/letsencrypt/live/YOUR_HOSTNAME.YOUR_COMPANY.COM/fullchain.pem nginx/ssl/cert.pem
sudo ln -sf /etc/letsencrypt/live/YOUR_HOSTNAME.YOUR_COMPANY.COM/privkey.pem nginx/ssl/key.pem
Automatische Erneuerung einrichten (nur Option C)
# Erneuerung testen
sudo certbot renew --dry-run
# Cron-Job zum Neuladen von nginx nach der Erneuerung
echo "0 3 * * * certbot renew --quiet --post-hook 'docker exec ipsolis-nginx nginx -s reload'" | sudo crontab -
nginx konfigurieren
Das Repository enthält bereits eine fertige nginx/nginx.conf mit dem Platzhalter YOUR_HOSTNAME.YOUR_COMPANY.COM. Den Platzhalter durch den tatsächlichen FQDN ersetzen (sed ersetzt beide Vorkommen in einem Schritt):
sudo sed -i 's/YOUR_HOSTNAME.YOUR_COMPANY.COM/ipsolis.firma.de/g' nginx/nginx.conf
Die Datei sieht danach so aus (zur Kontrolle):
server {
listen 80;
server_name YOUR_HOSTNAME.YOUR_COMPANY.COM;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name YOUR_HOSTNAME.YOUR_COMPANY.COM;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 2g;
# WebSocket / HTMX-Unterstützung
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
location / {
proxy_pass http://api:8000;
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;
}
}
Den tatsächlichen Hostnamen auch im Zertifikatsgenerierungsschritt (Option A/B/C) verwenden.
5. Produktions-Compose-Overlay
docker-compose.prelive.yml liegt bereits im Repository und muss nicht angelegt werden.
Das Overlay fügt nginx für die SSL-Terminierung hinzu und entfernt die Dev-Bind-Mounts
aus api und worker. Kein weiterer Schritt nötig.
6. Stack starten
cd /opt/ipsolis
# Alle Dienste bauen und starten
docker compose \
-f docker-compose.yml \
-f docker-compose.prelive.yml \
up --build -d
# Datenbankmigrationen ausführen
docker compose exec -T api alembic upgrade head
# Prüfen ob alle Container laufen
docker compose ps
Erwartete Ausgabe -- alle Dienste sollten Up (healthy) zeigen:
NAME STATUS
ipsolis-postgres Up (healthy)
ipsolis-redis Up (healthy)
ipsolis-api Up (healthy)
ipsolis-worker Up (healthy)
ipsolis-beat-1 Up
ipsolis-nginx Up
Anwendung überprüfen:
# Direkter API-Health-Check
curl -f http://localhost:8000/health | python3 -m json.tool
# Über nginx (HTTPS)
curl -fsk https://YOUR_HOSTNAME.YOUR_COMPANY.COM/health | python3 -m json.tool
7. Ersteinrichtung Administrator
Erstes Admin-Konto (RBAC)
https://YOUR_HOSTNAME.YOUR_COMPANY.COM/ui/ im Browser öffnen. Beim allerersten Aufruf
(wenn admin_users leer ist) zeigt die Login-Seite ein „Ersten Administrator anlegen"-Formular
anstelle des normalen Anmeldeformulars. Folgende Felder ausfüllen:
| Feld | Hinweise |
|---|---|
| Benutzername | 3–128 Zeichen, erlaubt: [a-zA-Z0-9._@-]+. Wird beim Speichern kleingeschrieben. |
| Passwort | Mindestens 12 Zeichen. PBKDF2-SHA256 / 600k Iterationen (OWASP-2023). |
| Passwort bestätigen | Muss übereinstimmen. |
Das Absenden erstellt den ersten Superadmin und meldet ihn direkt an. Dieser Vorgang ist idempotent gegenüber Race-Conditions -- wenn zwei Operatoren gleichzeitig das Formular abschicken, gewinnt nur einer; der andere erhält die Meldung, das Anmeldeformular zu verwenden.
Nach dem ersten Superadmin wechselt das Formular auf die reguläre Benutzername/Passwort-Anmeldung.
Weitere Admin-Benutzer anlegen
Nach der Anmeldung zu Admin-Benutzer in der linken Navigation navigieren (nur Superadmin). Pro-Benutzer-Konten in der jeweils passenden Rolle anlegen:
superadmin > admin > approver > auditor > helpdesk
Die vollständige Rollenhierarchie, Asset-Typ-spezifische ACL-Berechtigungen, Funktionstrennung und Passwortrichtlinien sind in der Admin-Oberfläche unter Einstellungen → Zugangskontrolle konfigurierbar.
Legacy-Fallback `ADMIN_API_KEY`
Der ADMIN_API_KEY aus .env authentifiziert weiterhin als virtueller Superadmin,
auch nach der Ersteinrichtung -- damit bestehende Skripte / X-Admin-Key-Header beim Update
nicht brechen. Verwendung auf der Login-Seite: Benutzername leer lassen, den Key als
Passwort eingeben. Das Audit-Log zeigt admin:legacy_key als Attribution, damit
Prüfer den Fallback-Pfad erkennen.
Für neue Integrationen werden per-Integration-API-Tokens empfohlen (Admin-Oberfläche → API-Tokens) -- benannte, ablaufende, widerrufliche Bearer-Tokens mit optionaler Rollenbindung und Berechtigungseinschränkung. Der Legacy-Shared-Key bleibt nur für Rückwärtskompatibilität.
Lizenz installieren
Für Evaluierung und nicht-kommerzielle Nutzung ist keine Lizenzdatei erforderlich. Für kommerzielle
Deployments stellt XenPool nach dem Kauf eine signierte .lic-Datei bereit.
Installation über die Admin-Oberfläche:
- Zu Admin → Lizenz navigieren (oder
https://YOUR_HOSTNAME.YOUR_COMPANY.COM/ui/licenseöffnen). - Lizenz hochladen klicken und die
ipsolis.lic-Datei auswählen. - Die Seite lädt mit Lizenznehmername und Ablaufdatum neu -- kein Neustart erforderlich.
Kulanzfrist: Bei Ablauf einer Lizenz gilt eine 30-tägige Kulanzfrist, bevor der Status auf „nicht lizenziert" zurückfällt. Die Admin-Oberfläche zeigt ein Warnbanner und der tägliche Health-Alert-E-Mail wird während dieser Zeit täglich versandt.
Überschreiben: Eine neue .lic kann jederzeit hochgeladen werden, um zu verlängern.
Die alte Datei wird ersetzt; der Lizenz-Cache wird beim nächsten Request aktualisiert
(mtime-basiert, kein Downtime).
Umgebungsvariablen-Override (Air-Gap / automatisierte Deployments): Die .lic-Datei in
den Container an einem alternativen Pfad einbinden und setzen:
IPSOLIS_LICENSE_PATH=/run/secrets/ipsolis.lic
Der Standardpfad ist /app/license/ipsolis.lic (innerhalb des ipsolis-api-Containers).
Docker-Secrets oder ein Bind-Mount funktionieren beides.
Konfigurationscheckliste
Die In-App-Setup-Checkliste (Dashboard → Setup checklist) führt durch alle erforderlichen Schritte. Die Reihenfolge hier entspricht der Checkliste:
1. Anwendungstitel und Logo setzen *(Essential)*
Zu Admin > Einstellungen → Allgemein navigieren:
| Einstellung | Beschreibung |
|---|---|
app.title |
Anwendungsname im Portal und in E-Mails (Standard: ip·Solis) |
app.logo |
Logo-Upload (PNG/SVG empfohlen) |
2. SMTP konfigurieren *(Essential)*
Zu Admin > Einstellungen → E-Mail navigieren:
| Einstellung | Beschreibung | Beispiel |
|---|---|---|
smtp.host |
SMTP-Relay-Hostname | smtp.ihreunternehmen.de |
smtp.port |
SMTP-Port | 587 |
smtp.user |
SMTP-Benutzername (falls Auth erforderlich) | selfservice@ihreunternehmen.de |
smtp.password |
SMTP-Passwort | (als Secret markiert) |
smtp.tls |
STARTTLS verwenden | true |
smtp.from |
Absender-E-Mail-Adresse | noreply@ihreunternehmen.de |
smtp.from_name |
Absender-Anzeigename | ip·Solis |
Zu Admin > E-Mail-Vorlagen navigieren, um Benachrichtigungstexte anzupassen.
3. Active Directory verbinden *(Essential)*
Zu Admin > Einstellungen → Active Directory navigieren:
| Einstellung | Beschreibung | Beispiel |
|---|---|---|
ad.server |
AD-Domänencontroller-Hostname oder IP | dc01.ihreunternehmen.de |
ad.port |
LDAP-Port | 389 (oder 636 für LDAPS) |
ad.base_dn |
Such-Base-DN | DC=ihreunternehmen,DC=de |
ad.domain |
NetBIOS-Domänenname | IHREUNTERNEHMEN |
ad.username |
Dienstkonto (sAMAccountName) | svc-selfservice |
ad.password |
Dienstkonto-Passwort | (als Secret markiert) |
ad.use_ssl |
LDAPS verwenden | true oder false |
Die erforderlichen AD-Berechtigungen hängen von den eingesetzten Modulen und Runbook-Schritten ab. Als Ausgangspunkt werden benötigt:
- Lesen auf Benutzerobjekte (Attribute:
displayName,sAMAccountName,userPrincipalName,manager,memberOf,distinguishedName)- Schreiben auf
memberan Gruppenobjekten — für AD-gruppenbasierte ZugriffszuweisungWeitergehende Berechtigungen (z. B. auf Computerobjekte, OUs oder andere Attribute) sind je nach verwendeten Runbooks und Modulen zusätzlich erforderlich.
4. Portal-SSO via Entra ID aktivieren *(Essential)*
Siehe Sektion 8 für die vollständige Entra-ID-Einrichtung.
5. Ersten Asset-Typ anlegen *(Essential)*
- Zu Admin > Asset-Typen > Neu navigieren
- Name, Beschreibung und Kategorie ausfüllen
- Automatisierungsstrategie konfigurieren (Gruppenzugriff, Runbook oder Zusammengesetzt)
- Bei Bedarf Genehmigungsanforderungen setzen
- Optional Zugriff mit einer Gruppe für berechtigte Antragsteller einschränken
- Speichern
6. Assets zum Pool hinzufügen *(Essential)*
Zu Admin > Asset-Pool > Neu navigieren und mindestens ein Asset anlegen.
Für reine
capacity_pooled-Asset-Typen (Kontingent ohne dedizierte Instanz) kann dieser Schritt übersprungen werden.
Runbooks einrichten *(falls zutreffend)*
ip·Solis wird mit einem vollständigen Beispiel-Runbook ausgeliefert: „Virtual Machine Recycler" — ein Standalone-Runbook, das alle erforderlichen Skript-Module (XenServer/XCP-ng, SCCM, Active Directory) bereits enthält und als Vorlage für eigene Automatisierungen genutzt werden kann.
Das Runbook ist unter Admin > Runbooks zu finden und kann dort direkt inspiziert, kopiert oder angepasst werden.
Eigene Runbooks für Asset-Typen anlegen:
- Zu Admin > Runbooks > Neu navigieren
- Schritte definieren (PowerShell-Module oder eingebaute Module)
- Das Runbook mit einem Asset-Typ verknüpfen
Beliebig viele eigene Runbooks mit individuellen Schritt-Kombinationen sind möglich.
Empfohlene weitere Schritte *(Recommended)*
- Microsoft Teams Genehmigungskarten: Zu Admin > Einstellungen → E-Mail navigieren und Teams-Webhook-URL hinterlegen — Genehmiger erhalten eine Adaptive Card mit Ein-Klick-Freigabelink zusätzlich zur E-Mail.
- Audit-Log an SIEM streamen: Unter Admin > Einstellungen → Compliance Splunk-HEC- oder Webhook-Endpunkt konfigurieren.
- Per-Integration-API-Token ausstellen: Unter Admin > API-Tokens benannte,
widerrufliche Bearer-Tokens für ServiceNow, Skripte oder Prometheus erstellen —
ersetzt den geteilten
X-Admin-Key.
Nach einem DB-Restore: Die
api_tokens-Tabelle wird mit wiederhergestellt. Unter Admin > API-Tokens alle Tokens prüfen — alte oder nicht mehr benötigte Tokens widerrufen und nur neue, dedizierte Tokens für aktive Integrationen ausstellen.
8. Entra ID SSO (Portal-Authentifizierung)
Das Self-Service-Portal unterstützt Microsoft Entra ID (Azure AD) für Single Sign-On.
App in Entra ID registrieren
- Im Azure-Portal zu App-Registrierungen > Neue Registrierung
- Name:
ip·Solis - Umleitungs-URI:
https://YOUR_HOSTNAME.YOUR_COMPANY.COM/portal/auth/callback(Web) - Anwendungs-ID (Client) und Verzeichnis-ID (Mandant) notieren
- Unter Zertifikate & Geheimnisse ein neues Client-Secret erstellen
In Admin-Oberfläche konfigurieren
Zu Admin > Einstellungen navigieren und einstellen:
| Einstellung | Beschreibung |
|---|---|
entra.mode |
entra_only (Entra-ID-Anmeldung erforderlich) oder entra_with_onprem (Entra ID + On-Premises-LDAP-Prüfung) |
entra.client_id |
Anwendungs-ID (Client) |
entra.client_secret |
Client-Secret-Wert (als Secret markiert) |
entra.tenant_id |
Verzeichnis-ID (Mandant) |
entra.redirect_uri |
https://YOUR_HOSTNAME.YOUR_COMPANY.COM/portal/auth/callback (ersetzen) |
entra.allowed_domains |
Kommagetrennte Liste erlaubter E-Mail-Domänen, z. B. ihreunternehmen.de |
Die Schaltfläche Entra-Verbindung testen zur Überprüfung der Konfiguration verwenden.
Wenn
entra.modeaufdisabledgesetzt ist, ist das Portal für jeden im Netzwerk mit einer gemeinsamen anonymen Identität offen -- jeder Besucher sieht dieselben Bestellungen und kann damit interagieren. Dies nur für Demo- / Air-Gap-Lab-Deployments verwenden. Für Mehrbenutzer-Produktionentra.mode = entra_onlysetzen.
9. Deployment überprüfen
Diese Checkliste durcharbeiten, um die korrekte Funktion zu bestätigen:
- HTTPS:
https://YOUR_HOSTNAME.YOUR_COMPANY.COMlädt mit gültigem Zertifikat - Admin-Oberfläche:
https://YOUR_HOSTNAME.YOUR_COMPANY.COM/ui/erreichbar - Ersteinrichtung: Admin-Login zeigt „Ersten Administrator anlegen"-Formular (oder bei vorhandenem Konto das reguläre Anmeldeformular ohne Fehler)
- Setup-Checkliste: Dashboard zeigt die In-App-Setup-Checkliste; grundlegende Punkte nach Konfiguration abhaken
- Portal-Anmeldung: Benutzer können sich per Entra ID SSO anmelden
- AD-Suche: Im Bestellformular werden Benutzer in Stellvertreter-, RDP- und Admin-Feldern korrekt aufgelöst
- E-Mail: Testbestellung einreichen und Eingang der Benachrichtigungs-E-Mail bestätigen
- Health-Check:
curl -fsk https://YOUR_HOSTNAME.YOUR_COMPANY.COM/healthgibt{"status": "ok"}zurück - (optional) API-Tokens: Per-Integration-Token für Automatisierungen ausstellen, die bisher
X-Admin-Keyverwenden - (optional) SIEM-Streaming: Unter Einstellungen → Compliance konfigurieren, falls Splunk / Sentinel / generischer Webhook-Empfänger vorhanden
- (optional) Prometheus:
/metricsvon der Monitoring-Lösung abfragen; das Dashboard liegt unter docs/grafana/
10. Backup & Wartung
Datenbank-Backup
Die PostgreSQL-Daten liegen in einem Docker-Volume (postgres_data). Regelmäßige Sicherungen durchführen:
# Datenbank dumpen
docker compose exec -T postgres pg_dump -U xpuser ipsolis > backup_$(date +%Y%m%d).sql
# Aus Backup wiederherstellen
cat backup_20260414.sql | docker compose exec -T postgres psql -U xpuser ipsolis
Logs
Container-Logs anzeigen:
# Alle Dienste
docker compose logs --tail=50
# Einzelner Dienst
docker compose logs api --tail=100 -f # Follow-Modus
docker compose logs worker --tail=100
Festplattenbereinigung
Alte Docker-Images regelmäßig entfernen:
docker image prune -f
11. Update auf neue Version
SSL-Vorprüfung — vor dem Pull ausführen. Fehlt eine der Dateien, startet der nginx-Container, liefert aber kein HTTPS.
ls -la nginx/ssl/cert.pem nginx/ssl/key.pemFalls Dateien fehlen, Zertifikat zuerst neu erstellen (siehe Abschnitt 4).
cd /opt/ipsolis
# Neuesten Code holen
git pull origin main
# Neu bauen und starten
docker compose \
-f docker-compose.yml \
-f docker-compose.prelive.yml \
up --build -d
# Neue Datenbankmigrationen ausführen
docker compose exec -T api alembic upgrade head
# nginx neu starten, um neue Container-IPs und ggf. geänderte Konfiguration zu übernehmen
docker compose \
-f docker-compose.yml \
-f docker-compose.prelive.yml \
restart nginx
# Gesundheit prüfen
curl -fsk https://YOUR_HOSTNAME.YOUR_COMPANY.COM/health | python3 -m json.tool
Migrationen können mehrfach ausgeführt werden -- Alembic verfolgt, welche bereits angewendet wurden, und überspringt diese. Jede Feature-Version bringt in der Regel eine eigene Migration mit;
api/alembic/versions/zwischen Updates auf Änderungen prüfen, unddocker compose exec api alembic historyzeigt die Migrationshistorie.
Backup vor dem Update
Immer zuerst die Datenbank sichern -- pg_dump aus dem Postgres-Container,
oder die In-App-Funktion Wartung → Backups (Admin-Oberfläche) verwenden,
die einen zeitgestempelten SQL-Dump in das eingebundene ./backups/-Verzeichnis schreibt.
Im selben Bereich einen täglichen Backup-Zeitplan konfigurieren, damit bei
einem unerwarteten Rückschritt eine frische Sicherung verfügbar ist.
Beat-HA-Failover während des Neustarts
Bei mehreren Beat-Replikas (--scale beat=N) rollt docker compose up --build -d
die Container nacheinander und die Leader-Sperre wechselt innerhalb von ~13 s auf
die verbleibende Replika über.
Bei Einzelinstallationen gibt es eine kurze Lücke während des Neustarts, in der
periodische Tasks nicht laufen -- in der Regel nicht merklich, da Intervalle
Minuten / Stunden betragen.
12. Hochverfügbarkeit
ip·Solis skaliert horizontal auf API- und Worker-Ebene. Der Beat-Scheduler unterstützt Multi-Replika-HA über celery-redbeat. Dieser Abschnitt beschreibt die beiden getesteten Skalierungsszenarien: API-Replikas und Worker-Replikas.
12.1 Multi-Replika-API
Die API ist zustandslos ausgelegt -- jede Replika bearbeitet jeden Request gleich, Sticky-Session-Affinität am Load Balancer ist nicht erforderlich.
Was sie zustandslos macht:
- Sessions verwenden Starletttes
`SessionMiddleware`
im Cookie-Signing-Modus (
api/app/main.py): Die gesamte Session-Nutzlast (Admin-User-ID, Rolle, CSRF-Token) liegt imxp_session-Cookie selbst, signiert mitAPI_SECRET_KEY. Keine serverseitige Session-Tabelle. - Tokenisierte URLs (
/approve/<token>,/portal/certifications/review/<token>usw.) sind HMAC-signiert mit demselbenAPI_SECRET_KEYund nur verifizierend. Keine Replay-Tabelle. - Jeder Request-Zustand liegt in Postgres oder Redis -- beides replika-übergreifend geteilt.
Was jede Replika teilen MUSS:
| Was | Warum | Wie |
|---|---|---|
API_SECRET_KEY |
Signiert Session-Cookies + Approval-Tokens. Verschiedene Keys pro Replika = Clients sehen "Session ungültig" / "Approval-Link abgelaufen" in der Hälfte der Fälle. | In .env fixieren; via env_file: in Compose laden, damit jede Replika dieselbe Datei liest. |
DATABASE_URL / CELERY_BROKER_URL / CELERY_RESULT_BACKEND |
Gemeinsames Postgres + Redis Backplane. | Wie oben. |
| Gemeinsame Filesystem-Mounts | licenses/, scripts/, backups/ sind bind-gemountet; Replikas, die dieselben Pfade lesen, müssen denselben Inhalt sehen. Auf einem Single-Host automatisch. Auf mehreren Hosts NFS / GlusterFS / einen gemeinsamen Volume-Treiber verwenden -- oder den Inhalt in S3-kompatiblen Objektspeicher migrieren. |
Single-Host-Deployments benötigen keine zusätzliche Infrastruktur. |
Skalierungsbefehle:
# Single-Host: API-Replika-Anzahl via Compose erhöhen
docker compose -f docker-compose.yml -f docker-compose.prelive.yml \
up -d --scale api=3
# Jede Replika über den Load Balancer prüfen
for i in 1 2 3; do
curl -fsk https://YOUR_HOSTNAME.YOUR_COMPANY.COM/health \
-H 'X-Replica-Probe: '$i
done
Load-Balancer-Konfigurationshinweise:
- Kein Sticky Session erforderlich. Round-Robin oder Least-Connections ist ausreichend.
- Health-Check:
GET /health(unauthentifiziert). Gibt{status: ok | degraded}zurück, aggregiert Datenbank-, Redis- und Beat-Liveness. Der Endpunkt ist schnell (ein Redis-Ping + ein DB SELECT 1), daher ist ein LB-Checkintervall von 5–10 s sinnvoll. - TLS-Terminierung: Am Load Balancer belassen (oder beim bestehenden nginx-Sidecar aus Abschnitt 5).
Replikas bearbeiten intern Plain-HTTP; das
https_only=True-Flag aufSessionMiddlewaresichert dasSecure-Bit des Cookies unabhängig davon, wo TLS terminiert.
Rolling-Restart beim Update: Der Update-Ablauf in Abschnitt 11 stoppt und startet alle
Replikas gemeinsam -- bei kleinen Flotten mit ~30 s API-Downtime akzeptabel. Für Zero-Downtime-
Rollouts den up --build -d-Schritt in eine Per-Replika-Schleife umwandeln:
for i in 1 2 3; do
docker compose stop api-$i
docker compose -f docker-compose.yml -f docker-compose.prelive.yml \
up --build -d --no-deps api-$i
# Warten bis der neue Container den Health-Check besteht
until curl -fsk http://localhost/health > /dev/null 2>&1; do
sleep 2
done
done
Dies setzt einen LB voraus, der einen Backend-Server gleichzeitig drainieren kann; beim Standard-Round-Robin nginx-Upstream gehen In-Flight-Requests der neustartenden Replika verloren. Die Drain-Logik liegt in der Verantwortung des Load Balancers.
12.2 Multi-Replika-Worker
Celery-Worker sind zustandslose Consumer -- sie lesen aus den benannten Redis-Queues und verarbeiten Tasks. Weitere Worker hinzuzufügen ist ein einzeiliges Scale-Up; der Worker-Code selbst ändert sich nicht.
Queue-Topologie (definiert in worker/tasks/__init__.py):
| Queue | Tasks | Warum separate Queue |
|---|---|---|
provision |
Bestellworkflows (dynamic_runner, standalone_runner, ps_module_installer, sccm_probe) -- alles, was AD / SCCM / vSphere / XenServer berührt. |
Provisionierungsschritte führen PowerShell aus (~5–60 s/Schritt) und halten Verbindungen zu externen Systemen. Isolation verhindert, dass ein langsamer vSphere-Aufruf schnelle Haushaltstasks blockiert. |
notifications |
E-Mail-Versand, Teams-Card-Zustellung, Approval-Reminder, Zertifizierungs-Reminder, Kostenbenachrichtigungen. | I/O-gebunden, latenzempfindlich (ein hängender SMTP-Server soll sich nicht hinter einem 30-s-SCCM-Probe einreihen). |
default |
Audit-Retention-Bereinigung, SIEM-Streaming, Lizenzprüfung, Update-Checker, Kostenbericht-Snapshot, DB-Backup, API-Token-Bereinigung. | Hintergrund-Housekeeping. Hauptsächlich cron-gesteuert, niedrige Frequenz. |
reclaim |
Asset-Ablauf-Prüfungen (check_expiring_assets). |
Stündlicher Beat-Task; klein, aber isoliert, damit der stündliche Tick nicht mit Bestellworkflows um einen Worker-Slot konkurriert. |
Dimensionsempfehlungen (Parallelität pro Queue × Replika-Anzahl):
| Pool-Größe | Empfohlene Konfiguration | Begründung |
|---|---|---|
| Lab / Einzelteam (≤50 Benutzer) | 1 Worker-Replika, --concurrency=4 -Q provision,notifications,default,reclaim |
Alle Queues in einem Prozess; Parallelität 4 reicht für typisch 1–2 Bestellungen/Stunde. |
| Mittel (≤500 Benutzer, ≤20 Bestellungen/Stunde) | 2 Worker-Replikas nach Queue aufgeteilt: Replika A -Q provision --concurrency=4, Replika B -Q notifications,default,reclaim --concurrency=2 |
Provisionierungslatenz bleibt durch Replika A begrenzt; Replika B erledigt Housekeeping + Erinnerungen ohne Head-of-Line-Blocking. |
| Groß (≥500 Benutzer, ≥50 Bestellungen/Stunde, regulierte SLAs) | 3+ Worker-Replikas: dedizierte provision-Worker (--concurrency=8 × 2 Replikas), eine notifications-Replika (--concurrency=4), eine default,reclaim-Replika (--concurrency=2) |
Per-Queue-Skalierung passt zur tatsächlichen Lastform. |
Skalierungsbefehl (Single-Host, alle Queues auf jeder Replika):
docker compose -f docker-compose.yml -f docker-compose.prelive.yml \
up -d --scale worker=3
Dedizierte Replikas pro Queue erfordern entweder separate Compose-Service-Definitionen
(z. B. worker-provision, worker-notifications) mit jeweils eigenem command: zum
Überschreiben der Standard-Queue-Liste, oder ein Runtime-command:-Override:
# docker-compose.prelive.yml — Queue-Aufteilung
services:
worker-provision:
image: ipsolis-worker
command: celery -A tasks worker -Q provision --concurrency=8 -l info
deploy: { replicas: 2 }
env_file: .env
worker-notifications:
image: ipsolis-worker
command: celery -A tasks worker -Q notifications --concurrency=4 -l info
deploy: { replicas: 1 }
env_file: .env
worker-housekeeping:
image: ipsolis-worker
command: celery -A tasks worker -Q default,reclaim --concurrency=2 -l info
deploy: { replicas: 1 }
env_file: .env
Beat-Skalierung: Der Beat-Container hat keinen festen container_name, damit er
repliziert werden kann. Für HA-Setups mit mehreren Beat-Instanzen:
docker compose \
-f docker-compose.yml \
-f docker-compose.prelive.yml \
up -d --scale beat=2
Hinweis: Celery Beat ist ein Singleton-Scheduler. Mehrere Beat-Replikas sind nur in Kombination mit
django-celery-beatodercelery-redbeat(bereits konfiguriert) sinnvoll — redbeat verhindert doppelte Task-Auslösung per Redis-Lock.
Liveness: Jeder Worker registriert sich beim Start via Celery-Mingle; ein frischer
Worker ist innerhalb weniger Sekunden für Beat / andere Worker sichtbar. Kein separater
Health-Check nötig -- wenn der Worker-Container Up ist, konsumiert er.
Sichtbarkeit: Flower (der bestehende flower-Dienst in der Dev-Compose; siehe
docker-compose.yml) zeigt Live-Worker-Registrierung, Queue-Tiefe und task-genaue
Dauern. Für Produktion mit derselben nginx-Auth wie die Admin-Oberfläche schützen;
Flower hat keine eingebaute Authentifizierung außer HTTP-Basic.
12.3 Postgres-Hochverfügbarkeit
Postgres-HA (Streaming Replication, pgBackRest, Patroni) ist architektonisch möglich,
da ip·Solis Single-Primary arbeitet und jeder Connection-String-Wechsel nur eine
.env-Änderung + Neustart erfordert. Eine geprüfte Schritt-für-Schritt-Anleitung
ist in dieser Version noch nicht enthalten.
13. Fehlerbehebung
Container startet nicht
# Container-Status und Exit-Codes prüfen
docker compose ps -a
# Logs des fehlerhaften Dienstes prüfen
docker compose logs <dienstname> --tail=50
Health-Check schlägt durch nginx fehl, aber API ist gesund
Nginx hat möglicherweise die alte Container-IP gecacht. Container neu starten
(nicht nur nginx -s reload — Docker bind-mounts behalten sonst den alten Inode):
docker compose \
-f docker-compose.yml \
-f docker-compose.prelive.yml \
restart nginx
Datenbankverbindungsfehler
# Prüfen ob postgres läuft
docker compose exec postgres pg_isready -U xpuser
# Verbindung vom API-Container testen
docker compose exec api python -c "
from sqlalchemy import create_engine, text
e = create_engine('postgresql://xpuser:<passwort>@postgres:5432/ipsolis')
with e.connect() as c: print(c.execute(text('SELECT 1')).scalar())
"
AD / LDAP-Verbindungsprobleme
- Netzwerkkonnektivität aus dem Container prüfen:
docker compose exec api curl -v telnet://dc01.ihreunternehmen.de:389 - AD-Einstellungen unter Admin > Einstellungen prüfen
- API-Logs auf LDAP-Fehler durchsuchen:
docker compose logs api 2>&1 | grep -i "ldap\|ad_lookup"
E-Mails werden nicht gesendet
- SMTP-Einstellungen unter Admin > Einstellungen prüfen
- Worker-Logs auf SMTP-Fehler prüfen:
docker compose logs worker 2>&1 | grep -i "smtp\|mail\|notification" - Erreichbarkeit des SMTP-Relays prüfen:
docker compose exec api curl -v telnet://smtp.ihreunternehmen.de:587
Zugriff verweigert auf ssl-Verzeichnis
sudo chmod 644 nginx/ssl/cert.pem
sudo chmod 600 nginx/ssl/key.pem
14. Sauberer Neustart (Testumgebungen)
Nur für Test- und Staging-Umgebungen. Dieser Abschnitt löscht alle Daten unwiderruflich. Niemals auf einer Produktionsinstanz ausführen.
Docker-Volumes (Datenbankdaten, Redis-Daten) überleben ein rm -rf /opt/ipsolis,
da sie unter /var/lib/docker/volumes/ gespeichert sind — unabhängig vom
Repository-Verzeichnis. Für eine vollständig saubere Neuinstallation:
# 1. Stack stoppen und Volumes löschen
cd /opt/ipsolis
docker compose \
-f docker-compose.yml \
-f docker-compose.prelive.yml \
down -v
# 2. Repository-Verzeichnis löschen
cd /opt
sudo rm -rf ipsolis
# 3. Neu installieren (ab Abschnitt 2)
sudo git clone https://github.com/XenPool/ipsolis.git ipsolis
cd ipsolis
Nach diesem Reset enthält die Datenbank keine Benutzer, keine Konfiguration und keine Assets — die Ersteinrichtung (Abschnitt 7) muss erneut durchgeführt werden.