tva
← Insights

Self-Hosting von Windmill auf Ubuntu: Vollständiges Docker-Setup-Tutorial mit PostgreSQL-Fehlerbehebung

Workflow-Automatisierungsplattformen sind für moderne Entwicklungsteams unverzichtbar, aber Cloud-Lösungen wie Windmill Cloud können mit steigender Nutzung teuer werden. Wir zeigen Ihnen, wie Sie Ihre eigene Windmill-Instanz auf Ubuntu mit Docker Compose und Traefik-Integration einrichten und dabei kritische PostgreSQL-Authentifizierungsprobleme überwinden, die Ihre Installation zum Scheitern bringen können.

Was Sie aufbauen werden

Am Ende dieses Tutorials verfügen Sie über:

  • Voll funktionsfähige Windmill-Installation mit HTTPS
  • Automatische SSL-Zertifikate über Let's Encrypt durch Traefik
  • Produktionsreife PostgreSQL-Datenbank mit korrekter Authentifizierung
  • Ressourcenoptimierte Worker-Konfiguration
  • Integration mit bestehender Docker-Infrastruktur
  • Produktionsreifes Setup für professionelle Workflow-Automatisierung

Monatliche Kosten: 4,51 € (CX11-Server) + Domainkosten – dieselbe Infrastruktur kann mehrere Automatisierungstools betreiben

Voraussetzungen

  • Ubuntu 24.04 LTS-Server mit installierten Docker und Docker Compose
  • Bestehendes Traefik-Reverse-Proxy-Setup (siehe unseren n8n-Setup-Leitfaden für die Traefik-Konfiguration)
  • Domainname, der auf Ihre Server-IP verweist
  • Mindestens 4 GB RAM und 2 vCPUs empfohlen
  • SSH-Zugang und grundlegende Kommandozeilenkenntnisse

Windmill verstehen

Windmill ist eine Open-Source-Workflow-Engine, die Folgendes bietet:

  • Visueller Workflow-Editor mit TypeScript/Python/Go-Unterstützung
  • Job-Scheduling und Ausführungsverwaltung
  • API-Integrationsfähigkeiten
  • Team-Kollaborationsfunktionen
  • Self-Hostbar ohne Nutzungslimits

Im Gegensatz zum knotenbasierten Ansatz von n8n konzentriert sich Windmill auf Code-First-Workflows mit einer leistungsstarken Entwicklungsumgebung.

Schritt 1: Servervorbereitung und Verzeichnisstruktur

Zunächst bereiten wir unsere Serverumgebung vor. Wir verwenden eine lebensmittelbasierte Namenskonvention für Windmill-Instanzen, um Konflikte zu vermeiden:

# Create Windmill directory (first instance: "pizza")
mkdir -p /opt/windmill-pizza
cd /opt/windmill-pizza

# Create required subdirectories
mkdir -p postgres-data windmill-data lsp-cache

# Verify directory structure
ls -la

Namenskonvention: Verwenden Sie einfache Lebensmittelnamen für mehrere Windmill-Instanzen:

  • Erste Instanz: pizza
  • Weitere Instanzen: pasta, salad, soup, burger usw.
  • Dies vermeidet Konflikte und erleichtert die Verwaltung

Schritt 2: Umgebungskonfiguration

Erstellen Sie eine sichere Umgebungsdatei mit korrekten Zugangsdaten:

# Generate a secure hex password (no special characters!)
SECURE_PASSWORD=$(openssl rand -hex 16)
echo "Generated password: $SECURE_PASSWORD"

# Create environment file
cat > /opt/windmill-pizza/.env << EOF
# Windmill Image Version
WM_IMAGE=ghcr.io/windmill-labs/windmill:main

# Database Configuration - SECURE PASSWORDS
DATABASE_URL=postgresql://postgres:${SECURE_PASSWORD}@windmill-db:5432/windmill_pizza?sslmode=disable
POSTGRES_PASSWORD=${SECURE_PASSWORD}
POSTGRES_DB=windmill_pizza
POSTGRES_USER=postgres

# Windmill Configuration
BASE_URL=https://windmill.yourdomain.com
RUST_LOG=info

# Worker Configuration
WORKER_GROUP=default
KEEP_JOB_DIR=false

# Instance Identifier
INSTANCE_NAME=pizza
EOF

Wichtig: Ersetzen Sie windmill.yourdomain.com durch Ihre tatsächliche Domain!

Schritt 3: Docker-Compose-Konfiguration

Erstellen Sie die Haupt-Docker-Compose-Konfiguration:

cat > /opt/windmill-pizza/docker-compose.yml << 'EOF'
version: "3.8"

services:
  # PostgreSQL Database for Windmill
  windmill-db:
    image: postgres:16
    container_name: windmill-pizza-db
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    networks:
      - proxy
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Windmill Server
  windmill-server:
    image: ${WM_IMAGE}
    container_name: windmill-pizza-server
    restart: unless-stopped
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - BASE_URL=${BASE_URL}
      - RUST_LOG=${RUST_LOG}
      - MODE=server
    networks:
      - proxy
    depends_on:
      windmill-db:
        condition: service_healthy
    volumes:
      - ./windmill-data:/tmp/windmill
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.windmill-pizza.rule=Host(`windmill.yourdomain.com`)"
      - "traefik.http.routers.windmill-pizza.entrypoints=https"
      - "traefik.http.routers.windmill-pizza.tls.certresolver=letsencrypt"
      - "traefik.http.services.windmill-pizza.loadbalancer.server.port=8000"

  # Windmill Worker
  windmill-worker:
    image: ${WM_IMAGE}
    container_name: windmill-pizza-worker
    restart: unless-stopped
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - BASE_URL=${BASE_URL}
      - RUST_LOG=${RUST_LOG}
      - MODE=worker
      - WORKER_GROUP=${WORKER_GROUP}
      - KEEP_JOB_DIR=${KEEP_JOB_DIR}
    networks:
      - proxy
    depends_on:
      windmill-db:
        condition: service_healthy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./windmill-data:/tmp/windmill
      - worker_dependency_cache:/tmp/windmill/cache
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 2G

networks:
  proxy:
    external: true

volumes:
  worker_dependency_cache:
    driver: local
EOF

Wichtig: Aktualisieren Sie die Domain in den Traefik-Labels entsprechend Ihrem Setup!

Schritt 4: Das PostgreSQL-Passwort-Problem (Kritisches Problem)

Hier scheitern die meisten Windmill-Installationen, und es erforderte erhebliche Fehlersuche, um die Ursache zu identifizieren:

Das Problem: Sonderzeichen in Passwörtern

Bei der Verwendung von openssl rand -base64 32 zur Passwortgenerierung erhalten Sie oft Sonderzeichen wie =@#% usw. Diese Zeichen verursachen PostgreSQL-Authentifizierungsfehler in Docker-Umgebungen, selbst wenn sie korrekt maskiert sind.

Beispiel eines problematischen Passworts:

# This WILL cause authentication failures:
PASSWORD="305t6m9KrChkvbyNEFLEYQ6pqAGlApn9rbJPH3D5y9g="

Die Lösung: Reine Hex-Passwörter

Verwenden Sie reine Hex-Passwörter, die keine Sonderzeichen enthalten:

# This WORKS reliably:
PASSWORD=$(openssl rand -hex 16)
# Example result: 5781b14ec0ec1bc184653ffa5e379411

Zusätzliche PostgreSQL-Konfigurationsprobleme

  1. Benutzerkonfiguration: Verwenden Sie postgres als Standardbenutzer, nicht benutzerdefinierte Benutzer wie windmill_user
  2. Volume-Persistenz: PostgreSQL ignoriert POSTGRES_PASSWORD-Umgebungsvariablen, wenn bestehende Datenvolumes andere Zugangsdaten enthalten
  3. URL-Format: Fügen Sie ?sslmode=disable in die Datenbank-URL für Docker-Umgebungen ein

Schritt 5: Installation und Start

Installieren wir nun Windmill mit unserer korrigierten Konfiguration:

cd /opt/windmill-pizza

# Verify configuration syntax
docker compose config --quiet

# Pull images
docker compose pull

# Start services
docker compose up -d

# Check status
docker compose ps

Sie sollten eine Ausgabe wie diese sehen:

NAME                    STATUS                    PORTS
windmill-pizza-db       Up (healthy)              5432/tcp
windmill-pizza-server   Up                        8000/tcp
windmill-pizza-worker   Up                        8000/tcp

Schritt 6: Fehlerbehebung häufiger Probleme

Problem 1: PostgreSQL-Authentifizierungsfehler

Symptome:

windmill-pizza-server | Error: password authentication failed for user "postgres"

Lösung:

# Stop containers
docker compose down --volumes

# Remove old data
rm -rf postgres-data/*

# Regenerate hex password
NEW_PASSWORD=$(openssl rand -hex 16)
sed -i "s/POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$NEW_PASSWORD/" .env
sed -i "s/:.*@/:$NEW_PASSWORD@/" .env

# Restart
docker compose up -d

Problem 2: Container startet nicht

Symptome:

  • Container beendet sich sofort
  • Ressourcenzuweisungsfehler

Lösung:

# Check container logs
docker logs windmill-pizza-server
docker logs windmill-pizza-db

# Check system resources
docker stats
free -h

Problem 3: SSL-Zertifikatsprobleme

Symptome:

  • HTTPS funktioniert nicht
  • Zertifikatsfehler

Lösung:

# Check Traefik logs
docker logs traefik

# Verify DNS resolution
nslookup windmill.yourdomain.com

# Restart Traefik if needed
docker restart traefik

Schritt 7: Zugang und Ersteinrichtung

Nach Abschluss der Installation:

  1. Windmill aufrufen: https://windmill.yourdomain.com
  2. Standard-Zugangsdaten:
    • E-Mail: admin@windmill.dev
    • Passwort: changeme
  3. Einrichtung abschließen:
    • Admin-Passwort ändern
    • Basis-URL konfigurieren
    • Benutzerkonten einrichten

Schritt 8: Ressourcenoptimierung

Speicherzuweisung (für 8-GB-Server)

Unsere Konfiguration weist Ressourcen effizient zu:

  • Windmill Server: ~800 MB
  • Windmill Worker: 2 GB (begrenzt)
  • PostgreSQL: ~500 MB
  • Systemreserve: ~4,7 GB

CPU-Zuweisung (für 4-vCPU-Server)

  • Worker: 1 vCPU (begrenzt)
  • Andere Dienste: 3 vCPUs (geteilt)

Skalierungsregel: 1 Worker pro vCPU mit jeweils 1–2 GB RAM

Schritt 9: Produktionshärtung

Backup-Skript erstellen

cat > /opt/windmill-pizza/backup.sh << 'EOF'
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p /opt/backups
docker compose exec windmill-db pg_dump -U postgres windmill_pizza > /opt/backups/windmill_pizza_${DATE}.sql
echo "Backup created: windmill_pizza_${DATE}.sql"
EOF

chmod +x /opt/windmill-pizza/backup.sh

Monitoring einrichten

# Monitor container health
docker compose ps

# Check resource usage
docker stats

# Monitor logs
docker compose logs -f windmill-server

Automatisierte Updates konfigurieren

cat > /opt/windmill-pizza/update.sh << 'EOF'
#!/bin/bash
cd /opt/windmill-pizza
docker compose pull
docker compose up -d --force-recreate
EOF

chmod +x /opt/windmill-pizza/update.sh

Schritt 10: Erweiterte Konfiguration

Integration mit bestehendem SMTP

Wenn Sie einen Mailserver haben (z. B. aus unserem n8n-Setup), integrieren Sie ihn:

# Add to docker-compose.yml environment for windmill-server:
- SMTP_HOST=mailserver
- SMTP_PORT=25
- SMTP_USERNAME=
- SMTP_PASSWORD=
- SMTP_FROM=noreply@yourdomain.com

Mehrere Windmill-Instanzen

Für Teams, die isolierte Umgebungen benötigen:

# Create second instance
cp -r /opt/windmill-pizza /opt/windmill-pasta

# Update configuration
sed -i 's/pizza/pasta/g' /opt/windmill-pasta/.env
sed -i 's/windmill.yourdomain.com/pasta.yourdomain.com/g' /opt/windmill-pasta/.env

# Generate new password
NEW_PASSWORD=$(openssl rand -hex 16)
sed -i "s/POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$NEW_PASSWORD/" /opt/windmill-pasta/.env

# Update docker-compose.yml
sed -i 's/pizza/pasta/g' /opt/windmill-pasta/docker-compose.yml
sed -i 's/windmill.yourdomain.com/pasta.yourdomain.com/g' /opt/windmill-pasta/docker-compose.yml

Sicherheitsaspekte

Netzwerkisolierung

  • PostgreSQL nur innerhalb des Docker-Netzwerks erreichbar
  • Keine externen Datenbankports freigegeben
  • HTTPS-Terminierung auf Traefik-Ebene

Ressourcenlimits

  • Worker-Container haben CPU- und Speicherlimits
  • Verhindert Ressourcenerschöpfungsangriffe
  • Konfigurierbar basierend auf Serverkapazität

SSL-Sicherheit

  • Automatische Let's-Encrypt-Zertifikate
  • HTTP-zu-HTTPS-Weiterleitungen
  • Moderne TLS-Konfiguration

Überwachung und Wartung

Wöchentliche Gesundheitschecks

# Container status
docker compose ps

# Resource usage
docker stats --no-stream

# Log analysis
docker compose logs | grep -i error

Monatliche Wartung

# Update containers
cd /opt/windmill-pizza
./update.sh

# Clean old data
docker system prune -f

# Backup database
./backup.sh

Kostenaufstellung und Vergleich

Monatliche Kosten

Self-Hosted-Setup:

  • Hetzner CX21 (4 GB RAM): 8,46 €/Monat
  • Domainkosten: ~1 €/Monat
  • Gesamt: ~9,50 €/Monat

Windmill Cloud im Vergleich:

  • Team-Plan: 30 $/Monat pro Benutzer
  • Einsparungen: 250 $+ jährlich für kleine Teams

Leistungsvorteile

Vorteile des Self-Hosting:

  • Unbegrenzte Workflow-Ausführungen
  • Keine externen Rate-Limits
  • Volle Datenkontrolle
  • Individuelle Integrationen
  • Flexible Ressourcenskalierung

Fehlerbehebungsreferenz

Schnelldiagnose

# Container health
docker compose ps | grep -E "(healthy|Up)"

# Network connectivity
docker network inspect proxy

# Database connection
docker compose exec windmill-db psql -U postgres -d windmill_pizza -c "SELECT version();"

# Log analysis
docker compose logs --tail 50 windmill-server | grep -E "(ERROR|WARN)"

Häufige Fehlermuster

  1. "password authentication failed" -- Verwenden Sie Hex-Passwörter, Volumes löschen
  2. "connection refused" -- Netzwerkkonfiguration überprüfen
  3. "certificate errors" -- DNS und Traefik-Setup verifizieren
  4. "out of memory" -- Worker-Ressourcenlimits anpassen

Skalierung Ihrer Windmill-Infrastruktur

Horizontale Skalierung

Für Hochlast-Umgebungen:

# Add additional workers
windmill-worker-2:
  image: ${WM_IMAGE}
  container_name: windmill-pizza-worker-2
  environment:
    - DATABASE_URL=${DATABASE_URL}
    - MODE=worker
    - WORKER_GROUP=heavy
  deploy:
    resources:
      limits:
        cpus: '2'
        memory: 4G

Vertikale Skalierung

Server-Ressourcen upgraden:

  • CX31 (8 GB RAM): 16,07 €/Monat für schwere Workloads
  • CX41 (16 GB RAM): 29,75 €/Monat für Enterprise-Nutzung

Integration mit bestehender Infrastruktur

Zusammenarbeit mit n8n

Wenn Sie bereits n8n betreiben (aus unseren früheren Tutorials):

  • Windmill behandelt Code-First-Workflows
  • n8n behandelt visuelle, einfache Automatisierungen
  • Beide teilen denselben Traefik-Proxy
  • Separate Datenbanken verhindern Konflikte

Gemeinsam genutzte Dienste

Bestehende Infrastruktur nutzen:

  • Traefik: Verwaltet SSL für alle Dienste
  • Mailserver: Gemeinsames SMTP für Benachrichtigungen
  • Monitoring: Einheitliches Logging und Metriken
  • Backups: Zentralisierte Backup-Strategie

Fazit

Self-Hosting von Windmill bietet Enterprise-Grade-Workflow-Automatisierung zu einem Bruchteil der Cloud-Hosting-Kosten. Der Schlüssel zum Erfolg ist das Verständnis der PostgreSQL-Authentifizierungsanforderungen und die Verwendung reiner Hex-Passwörter, um Sonderzeichenprobleme zu vermeiden, die Installationen zum Scheitern bringen können.

Wichtigste Vorteile dieses Setups

  • Kosteneffizient: Hunderte Euro jährlich sparen im Vergleich zu Cloud-Lösungen
  • Produktionsreif: Bewältigt Enterprise-Workloads zuverlässig
  • Sicher: HTTPS, isolierte Netzwerke und Ressourcenlimits
  • Skalierbar: Einfach Worker und Ressourcen nach Bedarf hinzufügen
  • Privat: Ihr Code und Ihre Daten verlassen nie Ihre Infrastruktur

Diese Konfiguration wurde in Produktionsumgebungen getestet und bietet die Zuverlässigkeit, die für geschäftskritische Workflow-Automatisierung benötigt wird. Die Fehlerbehebungsschritte behandeln reale Probleme, die beim Deployment aufgetreten sind, insbesondere die PostgreSQL-Authentifizierungsprobleme, die viele Self-Hosted-Installationen betreffen.

Für komplexe Workflow-Anforderungen oder Enterprise-Deployments sollten Sie professionelle Beratung in Betracht ziehen, um Ihren spezifischen Anwendungsfall zu optimieren und eine optimale Ressourcenzuweisung sicherzustellen.

Nächste Schritte


Über tva

tva gewährleistet umfassendes Infrastrukturmanagement von Datenbanksystemen, Cloud-Umgebungen und globalen Lieferketten. Unser methodischer Ansatz verbindet strenge Sicherheitsprotokolle mit Leistungsoptimierung, während strategische Beratungsdienstleistungen eine präzise Koordination sowohl digitaler Fähigkeiten als auch physischer Ressourcen ermöglichen – unter Einhaltung höchster Standards operativer Exzellenz und Compliance in allen Engagements.

Besuchen Sie tva.sg für weitere Informationen über unsere Dienstleistungen und zusätzliche Automatisierungs-Tutorials.