On-Premise-Installation¶
Voraussetzungen¶
Serveranforderungen: - Linux-Server (Ubuntu 22.04+, Debian 12+, RHEL 9+ oder jedes Docker-fähige OS) - Docker Engine 24.0+ - Docker Compose v2.20+ - Git - Mindestens 4 GB RAM (8 GB empfohlen; mehr API-Prozesse benötigen mehr, siehe Konfiguration) - Mindestens 20 GB Festplatte (+ Build-Cache)
Vom Kunden bereitgestellte Infrastruktur:
| Komponente | Anforderung |
|---|---|
| PostgreSQL | Version 16+ mit den Erweiterungen citext, pgcrypto, uuid-ossp und einer dedizierten Anwendungsrolle für DATABASE_URL |
| S3-Speicher | Jeder S3-kompatible: AWS S3, MinIO, Cloudflare R2, Hetzner usw. |
| Reverse Proxy | TLS-Terminierung und Routing (nginx, Traefik, Caddy usw.) |
| Domain | DNS-Eintrag, der auf Ihren Server zeigt |
Optional:
- Konfiguration für ausgehende E-Mail: Resend API-Schlüssel oder SMTP-Relay/Server-Details
- Microsoft Entra SSO (siehe sso-entra.md)
Schnellstart¶
# 1. Repository klonen
git clone https://github.com/kanap-it/kanap.git
cd kanap
# 2. Umgebung konfigurieren VOR dem Bauen
cp infra/.env.onprem.example .env
nano .env # DATABASE_URL, S3-Credentials, ADMIN_EMAIL, JWT_SECRET, APP_BASE_URL, CORS_ORIGINS setzen
# (APP_BASE_URL und CORS_ORIGINS: die genaue Adresse, die Benutzer öffnen)
# APP_ENV=production ergänzen, sobald Benutzer KANAP über HTTPS erreichen
# Siehe den Konfigurationsleitfaden für alle Variablen
# 3. Docker-Images bauen (Compose baut sie aus dem Repository)
docker compose -f infra/compose.onprem.yml build --pull
# 4. Container starten
docker compose -f infra/compose.onprem.yml up -d
# 5. Start überprüfen
docker compose -f infra/compose.onprem.yml logs -f api
# Auf "[entrypoint] Migrations complete" und danach "Nest application successfully started" warten
# Beim ersten Start erstellt KANAP automatisch Mandant, Admin-Benutzer und Abonnement
# 6. Ihren Reverse Proxy konfigurieren, um Traffic zu routen an:
# - /api/* → api:8080
# - /* → web:80
# Stellen Sie sicher, dass der Proxy Host beibehält und X-Forwarded-Proto setzt.
# Lesen Sie nach dem ersten Start die Zeilen [ENV], [CONFIG] und [CORS] im API-Protokoll.
# 7. Auf Anwendung zugreifen
# https://kanap.ihre-domain.de
# Mit ADMIN_EMAIL / ADMIN_PASSWORD aus .env anmelden
Wichtig: Schließen Sie die Konfiguration (Schritt 2) ab, bevor Sie Container starten. Die API liest .env beim Start und erstellt beim ersten Start den Mandanten und Admin-Benutzer mit diesen Werten.
Datenbankrollen-Anforderung: DATABASE_URL muss eine dedizierte PostgreSQL-Anwendungsrolle verwenden. Zeigen Sie nicht auf postgres oder eine andere Cluster-Admin-Rolle. KANAP verweigert den Start, anstatt ohne effektive RLS-Durchsetzung zu laufen.
Adresse und Origins: Setzen Sie APP_BASE_URL und CORS_ORIGINS auf die genaue Adresse, die Benutzer öffnen, mit dem Port, wenn er nicht dem Standard entspricht. Jeder Link, den KANAP versendet, stammt aus APP_BASE_URL. Ergänzen Sie APP_ENV=production, wenn Benutzer KANAP über HTTPS erreichen: Die API startet dann nicht ohne diese beiden Werte und markiert das Sitzungs-Cookie immer als Secure. Siehe Konfiguration.
E-Mail-Wahl: On-Premise-Bereitstellungen können entweder Resend oder SMTP für ausgehende E-Mail verwenden. SMTP ist nützlich, wenn der Kunde bereits ein internes Mail-Relay oder einen verwalteten Anbieter wie Microsoft 365 hat. Konfigurieren Sie eine dieser Optionen, wenn Sie möchten, dass Passwortzurücksetzung, Einladungen und Benachrichtigungs-E-Mails ab dem ersten Tag funktionieren.
Reverse-Proxy-Beispiel (nginx)¶
Reverse-Proxy-Anforderungen:
- TLS auf Port 443 terminieren
/api/*an den API-Container routen (Port 8080)- Alle anderen Anfragen an den Web-Container routen (Port 80)
X-Forwarded-Proto: httpssetzen undHostbeibehalten. KANAP erstellt die Links, die es versendet, ausAPP_BASE_URLund liestX-Forwarded-Hostaußerhalb der lokalen Entwicklung nicht mehr. Verwendet die Website einen nicht standardmäßigen Port, tragen Sie die genaue Adresse mit Port inCORS_ORIGINSein.- WebSocket-Upgrade unterstützen (verwendet für Echtzeit-Funktionen)
Da Container an 127.0.0.1 gebunden sind, läuft nginx auf dem gleichen Host und proxyt zu localhost.
server {
# HTTP/2: Der Browser sendet die Dutzenden Anfragen einer Seite über eine Verbindung.
# nginx 1.25.1 und neuer: Schreiben Sie stattdessen `listen 443 ssl;` und `http2 on;`.
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name kanap.company.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
# Datei-Upload-Limit (KANAP unterstützt bis zu 20 MB)
client_max_body_size 20m;
# /api → /api/ kanonisieren
location = /api { return 301 /api/; }
# API: /api-Präfix vor dem Proxying entfernen
location ^~ /api/ {
proxy_pass http://127.0.0.1:8080/;
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_set_header X-Forwarded-Host $host;
# Komprimiert die JSON- und CSV-Antworten der API (eine Budgetlisten-Seite wird etwa 8-mal kleiner).
# Gestreamte KI-Antworten (application/x-ndjson) sind absichtlich ausgenommen.
gzip on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_vary on;
gzip_types application/json text/csv text/plain;
# WebSocket-Unterstützung
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Lang laufende Anfragen (Exporte, Importe)
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_redirect off;
}
# Alles andere → SPA
location / {
proxy_pass http://127.0.0.1:8081;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
}
}
server {
listen 80;
listen [::]:80;
server_name kanap.company.com;
return 301 https://$host$request_uri;
}
Kompression und HTTP/2: Das Beispiel komprimiert die Antworten der API und aktiviert HTTP/2. Behalten Sie beides in Ihrem eigenen Proxy: Eine Seite der Budgetliste wiegt unkomprimiert etwa 390 KB JSON und komprimiert 47 KB. Hat Ihr nginx das Brotli-Modul (libnginx-mod-http-brotli-filter unter Debian und Ubuntu), komprimiert brotli on; brotli_types application/json text/csv text/plain; im selben location-Block etwas besser; gzip reicht aus.
Selbstsigniertes TLS (keine Domain): Wenn Sie keine Domain haben und per IP-Adresse auf KANAP zugreifen, erstellen Sie ein selbstsigniertes Zertifikat:
sudo mkdir -p /etc/ssl/kanap
sudo openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 \
-keyout /etc/ssl/kanap/server.key \
-out /etc/ssl/kanap/server.crt \
-subj "/CN=IHRE_IP" \
-addext "subjectAltName=IP:IHRE_IP"
Ersetzen Sie IHRE_IP durch die IP-Adresse Ihres Servers und aktualisieren Sie server_name, APP_BASE_URL und CORS_ORIGINS entsprechend. Benutzer müssen beim ersten Zugriff die Browser-Zertifikatswarnung akzeptieren.
host.docker.internal: Wenn PostgreSQL oder S3-Speicher auf dem Docker-Host laufen (nicht in einem Container), verwenden Sie host.docker.internal als Hostname in DATABASE_URL und S3_ENDPOINT. Die Datei compose.onprem.yml enthält das extra_hosts-Mapping, das dies ermöglicht.
Netzwerkarchitektur¶
┌─────────────────────────────────────────────────────┐
│ Kunden-Infrastruktur │
│ │
Internet │ ┌──────────────┐ ┌─────────────────────────┐ │
│ │ │ Ihr Reverse │ │ Docker-Host │ │
│ │ │ Proxy │ │ │ │
┌────▼────┐ │ │ (TLS) │ │ ┌─────┐ ┌─────┐ │ │
│ Browser │──────┼─▶│ :443 │───▶│ │ api │ │ web │ │ │
└─────────┘ │ └──────────────┘ │ │:8080│ │ :80 │ │ │
│ │ └─────┘ └─────┘ │ │
│ ┌──────────────┐ └─────────────────────────┘ │
│ │ PostgreSQL │ │
│ │ (Ihres) │◀──────── DATABASE_URL │
│ └──────────────┘ │
│ ┌──────────────┐ │
│ │ S3-Speicher │◀──────── S3_ENDPOINT │
│ │ (Ihres) │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────┘
Deployment-Modell: ein API-Container und ein Web-Container. Der Betrieb mehrerer API- oder Web-Container wird nicht unterstützt. Für mehr gleichzeitige Benutzer führen Sie mehrere API-Prozesse innerhalb des API-Containers mit API_WORKERS aus (siehe Konfiguration). Für Hochverfügbarkeit verlassen Sie sich auf Docker-Neustart-Richtlinien und Infrastruktur-Redundanz (Datenbank-HA, S3-Haltbarkeit).
Erste Anmeldung¶
- Navigieren Sie zu
https://<ihre-domain> - Melden Sie sich mit den Zugangsdaten aus
.envan (ADMIN_EMAIL / ADMIN_PASSWORD) - Ändern Sie sofort das Admin-Passwort über das Benutzerprofil
- Konfigurieren Sie Organisationseinstellungen
- Laden Sie weitere Benutzer ein (wenn E-Mail konfiguriert ist)