Zum Hauptinhalt springen

sol2flow mit Docker Compose installieren

Ein selbst gehostetes sol2flow besteht aus einem Container (Web-App, API und Hintergrundjobs) plus einer PostgreSQL-Datenbank (16, 17 oder 18; 18 empfohlen). Hochgeladene Dateien landen auf einem Volume oder in S3-kompatiblem Speicher. E-Mails gehen per SMTP hinaus.

Voraussetzungen​

  • Ein Linux-Server (x86-64 oder ARM64) mit Docker und dem Docker Compose-Plugin.
  • 1 CPU und 1–2 GB Arbeitsspeicher für ein kleines Team; mehr für viele Benutzer oder große Importe.
  • Ein Domainname, der auf den Server zeigt, und ein Reverse-Proxy für HTTPS (Reverse-Proxy und TLS).
  • Ein SMTP-Konto zum Versenden von E-Mails (E-Mail).
  • Speicherplatz für die Datenbank und für Uploads, plus Platz für Backups.
  • PostgreSQL 16, 17 oder 18 (18 empfohlen). Die compose.yml unten bringt 18 mit; Sie nutzen schon 16 oder 17? Siehe PostgreSQL aktualisieren.

Das Image ist ghcr.io/sol2flow/sol2flow. Tags: latest, ein Release wie 1.2.3 oder eine Minor-Linie wie 1.2. Legen Sie in Produktion eine feste Version fest, damit Upgrades dann passieren, wenn Sie es wollen.

1. Ein Verzeichnis vorbereiten​

sudo mkdir -p /srv/sol2flow && cd /srv/sol2flow

Legen Sie compose.yml an:

name: sol2flow
services:
app:
image: ghcr.io/sol2flow/sol2flow:${SOL2FLOW_VERSION:-latest}
restart: unless-stopped
env_file: .env
environment:
DATABASE_URL: postgresql://sol2flow:${POSTGRES_PASSWORD:-sol2flow}@db:5432/sol2flow?schema=public
ports: ["127.0.0.1:3000:3000"] # only the reverse proxy on this host talks to the app
volumes: [uploads:/data/uploads, logs:/data/logs] # logs: only used with LOG_FILE
depends_on: { db: { condition: service_healthy } }
db:
image: postgres:18-alpine
restart: unless-stopped
environment: { POSTGRES_USER: sol2flow, POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-sol2flow}", POSTGRES_DB: sol2flow }
volumes: [pgdata:/var/lib/postgresql] # from PostgreSQL 18 not …/data (data: …/18/docker)
healthcheck: { test: ["CMD-SHELL", "pg_isready -U sol2flow"], interval: 5s, retries: 20 }
volumes: { pgdata: {}, uploads: {}, logs: {} }

Die App läuft als Benutzer und Gruppe 1001, nicht als root, und besitzt im Image /data/uploads und /data/logs. Benannte Volumes wie die oben übernehmen das von selbst. Um die Dateien stattdessen in einem Verzeichnis des Hosts abzulegen (ein Bind-Mount wie /srv/sol2flow/uploads:/data/uploads), übergeben Sie es zuerst diesem Benutzer:

sudo mkdir -p /srv/sol2flow/uploads /srv/sol2flow/logs
sudo chown -R 1001:1001 /srv/sol2flow/uploads /srv/sol2flow/logs

2. Konfigurieren​

Legen Sie daneben eine .env an. Das Minimum für Produktion:

SOL2FLOW_VERSION=latest
APP_URL=https://flow.example.com
AUTH_SECRET=<openssl rand -base64 32>
APP_ENCRYPTION_KEY=<openssl rand -base64 32>
POSTGRES_PASSWORD=<openssl rand -hex 16>

MAIL_DRIVER=smtp
MAIL_FROM="sol2flow <[email protected]>"
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_PASSWORD=<your SMTP password>

BOOTSTRAP_ADMIN_EMAIL=[email protected]
BOOTSTRAP_ADMIN_USERNAME=admin
BOOTSTRAP_ADMIN_PASSWORD=<a long password>

Ersetzen Sie jedes <…> durch einen echten Wert. Machen Sie .env nur für root lesbar (chmod 600 .env).

APP_ENCRYPTION_KEY sicher aufbewahren

APP_ENCRYPTION_KEY verschlüsselt Secrets, die in der Datenbank gespeichert sind (Secrets von Identity-Providern, Zwei-Faktor-Secrets, Webhook-Secrets). Bewahren Sie eine Kopie außerhalb des Servers und außerhalb Ihrer Datenbank-Backups auf. Geht der Schlüssel verloren oder wird er geändert, sind diese Secrets nicht mehr lesbar. Siehe Backups und Upgrades.

Alle Variablen sind unter Konfiguration beschrieben.

3. Starten​

docker compose pull
docker compose up -d
docker compose logs -f app

Bei jedem Start wendet die App ausstehende Datenbankmigrationen an und startet dann den Server auf Port 3000. Zwei Endpunkte zeigen, dass sie läuft:

  • /api/health antwortet, wenn der Prozess läuft.
  • /api/ready antwortet, wenn zusätzlich die Datenbank erreichbar ist.
curl -fsS http://127.0.0.1:3000/api/ready

4. HTTPS davorschalten​

Richten Sie Ihren Reverse-Proxy auf 127.0.0.1:3000 und liefern Sie die App unter Ihrer Domain aus: Reverse-Proxy und TLS. APP_URL muss exakt die Adresse sein, die Personen eingeben (Schema, Host und Port, falls nicht der Standardport).

5. Der erste Administrator​

Ist BOOTSTRAP_ADMIN_PASSWORD gesetzt, legt der erste Start das Konto aus den BOOTSTRAP_ADMIN_*-Variablen als Owner der Instanz an, die höchste Staff-Rolle. Der Benutzername ist admin, sofern Sie keinen anderen setzen; die E-Mail-Adresse ist optional. Das geschieht nur, solange die Instanz keine Benutzer hat; Sie können BOOTSTRAP_ADMIN_PASSWORD danach also aus der .env entfernen. Seine E-Mail-Adresse gilt als bestätigt, ebenso die Adresse jedes Kontos, das das Skript create-admin unten anlegt.

Eine neue Instanz startet leer: Dieses Konto ist ihr einziges, und es gibt keine Demodaten. Die integrierten Board-Vorlagen sind von Anfang an da.

Ohne BOOTSTRAP_ADMIN_PASSWORD legen Sie den Owner über die Kommandozeile an:

docker compose exec app node scripts/create-admin.mjs <username> <email> <password>

Das Skript funktioniert auch später:

  • Solange die Instanz keinen Owner hat, legt es einen Owner an (oder befördert ein Konto dazu); sonst einen Admin.
  • Mit --role owner|admin|support|auditor wählen Sie eine andere Staff-Rolle, zum Beispiel docker compose exec app node scripts/create-admin.mjs lea [email protected] '…' --role support.
  • Ein vorhandenes Konto behält sein Passwort und erhält die Rolle. Das Skript stuft einen vorhandenen Owner nie herab; Rollen ändern Sie unter Admin → Benutzer.

Was jede Rolle darf: Staff-Rollen.

6. Nach der ersten Anmeldung​

  1. Admin → Allgemein: Name der Instanz, Upload-Limits, Benachrichtigungs-E-Mails. Siehe Instanz-Einstellungen.
  2. Admin → Authentifizierung: Anmeldung per Passwort, Selbstregistrierung, Single Sign-on. Siehe Anmeldung.
  3. Schicken Sie sich selbst einen Passwort-Reset, um zu prüfen, ob der E-Mail-Versand funktioniert.
  4. Richten Sie Backups ein, bevor echte Daten hinzukommen.

Separater Worker (optional)​

Hintergrundarbeit (E-Mails, Aufräumarbeiten, Exporte, Importe, Webhooks) läuft im App-Container. Auf einer stark genutzten Instanz können Sie sie in einen eigenen Container auslagern:

  1. Setzen Sie ROLE=web auf den Containern, die Benutzer bedienen: Sie führen dann keine Hintergrundjobs mehr aus.
  2. Fügen Sie einen weiteren Service mit demselben Image und derselben .env hinzu, mit ROLE=worker und ohne veröffentlichten Port. Er führt die Jobs aus.