tva
← Insights

Windmill auf Ubuntu selbst betreiben: Vollständiges Docker-Setup-Tutorial mit PostgreSQL-Fehlerbehebung

Plattformen für Workflow-Automatisierung 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 beheben, die Ihre Installation zum Scheitern bringen können.

Was Sie einrichten werden

Am Ende dieses Tutorials verfügen Sie über:

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

Monatliche Kosten: ab 5,99 € zzgl. USt., inkl. einer primären IPv4-Adresse (Hetzner CX23, 4 GB RAM, Stand Oktober 2026) + Domainkosten – dieselbe Infrastruktur kann mehrere Automatisierungstools betreiben

Voraussetzungen

  • Server mit Ubuntu 24.04 LTS sowie installiertem 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
  • Zeitplanung von Jobs und Ausführungsverwaltung
  • Möglichkeiten zur API-Integration
  • Funktionen für die Zusammenarbeit im Team
  • Selbst betreibbar, mit unbegrenzten Ausführungen in der kostenlosen Community Edition

Im Gegensatz zum Node-basierten Ansatz von n8n konzentriert sich Windmill auf codeorientierte Workflows und bietet dafür eine leistungsstarke Entwicklungsumgebung.

Schritt 1: Servervorbereitung und Verzeichnisstruktur

Zunächst bereiten wir unsere Serverumgebung vor. Um Konflikte zu vermeiden, benennen wir Windmill-Instanzen nach Speisen:

# 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 für mehrere Windmill-Instanzen einfache Bezeichnungen für Speisen:

  • 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-pizza-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
chmod 600 /opt/windmill-pizza/.env

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

Schritt 3: Docker-Compose-Konfiguration

Erstellen Sie die zentrale 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-Passwortproblem (kritisches Problem)

An diesem Punkt scheitern die meisten Windmill-Installationen. Es war eine aufwendige Fehlersuche nötig, um die Ursache zu finden:

Das Problem: Sonderzeichen in Passwörtern

Bei der Verwendung von openssl rand -base64 32 zur Passwortgenerierung kann die Ausgabe +, / und = enthalten. In DATABASE_URL müssen diese Zeichen prozentkodiert werden; andernfalls können sie die URL-Verarbeitung stören und zu PostgreSQL-Authentifizierungsfehlern führen. Passwörter aus Hexadezimalzeichen machen diesen Kodierungsschritt überflüssig.

Beispiel eines problematischen Passworts:

# This WILL cause authentication failures:
PASSWORD="305t6m9KrC/kvbyNEF+EYQ6pqAGlApn9rbJPH3D5y9g="

Die Lösung: Passwörter ausschließlich aus Hexadezimalzeichen

Verwenden Sie Passwörter ausschließlich aus Hexadezimalzeichen, die keine Sonderzeichen enthalten:

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

Zusätzliche PostgreSQL-Konfigurationsprobleme

  1. Benutzerkonfiguration: Verwenden Sie den Superuser postgres, wie in der Beispielkonfiguration von Windmill. Ein benutzerdefinierter Benutzer funktioniert erst, nachdem ihm die Rollen windmill_admin und windmill_user zugewiesen wurden, die die Migrationen von Windmill benötigen (siehe die Self-Hosting-Dokumentation von Windmill)
  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 ein, wenn die Datenbank wie in der Beispielkonfiguration von Windmill nur über das interne Docker-Netzwerk erreichbar ist; verwenden Sie für Datenbanken, die über andere Netzwerke erreicht werden, einen SSL-Modus wie require

Schritt 5: Installation und Start

Installieren Sie nun Windmill mit der 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: Häufige Probleme beheben

Problem 1: PostgreSQL-Authentifizierungsfehler

Symptome:

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

Lösung: Dabei werden alle Windmill-Datenbankdaten gelöscht. Verwenden Sie dieses Verfahren nur bei einer Neuinstallation oder nach einem überprüften Backup. Die beiden sed-Befehle schreiben das neue Passwort in POSTGRES_PASSWORD und DATABASE_URL.

# 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#postgresql://postgres:[^@]*@#postgresql://postgres:$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:
  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 (gemeinsam genutzt)

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

Schritt 9: Sicherheitshärtung für den Produktivbetrieb

Backup-Skript erstellen

cat > /opt/windmill-pizza/backup.sh << 'EOF'
#!/bin/bash
set -euo pipefail
cd /opt/windmill-pizza
DATE=$(date +%Y%m%d_%H%M%S)
FILE=/opt/backups/windmill_pizza_${DATE}.sql
mkdir -p /opt/backups
if ! docker compose exec -T windmill-db pg_dump -U postgres windmill_pizza > "$FILE"; then
  rm -f "$FILE"
  echo "Backup failed" >&2
  exit 1
fi
echo "Backup created: $FILE"
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=
- [email protected]

Mehrere Windmill-Instanzen

Für Teams, die isolierte Umgebungen benötigen erhält die zweite Instanz eigene leere Datenverzeichnisse, eine eigene Datenbank und ein eigenes Passwort:

# Create second instance with its own empty data directories
mkdir -p /opt/windmill-pasta/postgres-data /opt/windmill-pasta/windmill-data /opt/windmill-pasta/lsp-cache
cp /opt/windmill-pizza/.env /opt/windmill-pizza/docker-compose.yml /opt/windmill-pasta/
chmod 600 /opt/windmill-pasta/.env

# 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
sed -i "s#postgresql://postgres:[^@]*@#postgresql://postgres:$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 ist nur von Containern im gemeinsamen Docker-Netzwerk proxy aus erreichbar; verwenden Sie für eine strengere Isolation ein separates internes Netzwerk
  • Keine externen Datenbankports freigegeben
  • HTTPS-Terminierung auf Traefik-Ebene

Ressourcenlimits

  • Worker-Container haben CPU- und Speicherlimits
  • Ressourcenlimits verringern die Auswirkungen außer Kontrolle geratener Jobs und von Versuchen, Ressourcen zu erschöpfen
  • An die Serverkapazität anpassbar

SSL-Sicherheit

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

Überwachung und Wartung

Wöchentliche Zustandsprüfungen

# Container status
docker compose ps

# Resource usage
docker stats --no-stream

# Log analysis
docker compose logs | grep -i error

Monatliche Wartung

# Backup database first
cd /opt/windmill-pizza
./backup.sh

# Update containers
./update.sh

# Clean old data
docker system prune -f

Kostenaufstellung und Vergleich

Monatliche Kosten

Selbst betriebenes Setup:

  • Hetzner CX23 (4 GB RAM): 5,99 €/Monat zzgl. USt., inkl. einer primären IPv4-Adresse (Stand Oktober 2026)
  • Domainkosten: ~1 €/Monat
  • Gesamt: ~7 €/Monat zzgl. USt.

Windmill Cloud im Vergleich:

  • Cloud: 20 $/Monat pro Entwicklerplatz, 10 $/Monat pro Operator (Stand Oktober 2026)
  • Einsparungen: 250 $+ jährlich, sobald mindestens zwei Entwickler einen Platz benötigen

Leistungsvorteile

Vorteile des Self-Hostings:

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

Fehlerbehebung zum Nachschlagen

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 Passwörter aus Hexadezimalzeichen; löschen Sie die Volumes nur nach einem Backup oder bei einer Neuinstallation
  2. "connection refused" – Prüfen Sie die Netzwerkkonfiguration
  3. "certificate errors" – Prüfen Sie DNS und das Traefik-Setup
  4. "out of memory" – Passen Sie die Ressourcenlimits der Worker an

Skalierung Ihrer Windmill-Infrastruktur

Horizontale Skalierung

Für Umgebungen mit hoher Last:

# 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

Serverressourcen erweitern (Hetzner-Preise zzgl. USt., inkl. einer primären IPv4-Adresse, Stand Oktober 2026):

  • CX33 (8 GB RAM): 8,99 €/Monat für anspruchsvolle Workloads
  • CX43 (16 GB RAM): 16,49 €/Monat für den Unternehmenseinsatz

Integration mit bestehender Infrastruktur

Zusammenarbeit mit n8n

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

  • Windmill führt Workflows aus, bei denen der Code im Mittelpunkt steht
  • n8n führt einfache, visuell erstellte Automatisierungen aus
  • 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 Workflow-Automatisierung auf Unternehmensniveau zu einem Bruchteil der Cloud-Hosting-Kosten. Der Schlüssel zum Erfolg ist das Verständnis dafür, wie PostgreSQL-Zugangsdaten übergeben und dauerhaft gespeichert werden, und die Verwendung von Passwörtern ausschließlich aus Hexadezimalzeichen, um Probleme mit der URL-Kodierung zu vermeiden, die Installationen zum Scheitern bringen können.

Wichtigste Vorteile dieses Setups

  • Kosteneffizient: Jährlich Hunderte sparen im Vergleich zu Cloud-Lösungen
  • Produktionsreif: Bewältigt Arbeitslasten im Unternehmen zuverlässig
  • Sicher: HTTPS, kein nach außen freigegebener Datenbankport und Ressourcenlimits (der eingebundene Docker-Socket gibt dem Worker weiterhin Zugriff auf Host-Ebene)
  • Skalierbar: Einfach Worker und Ressourcen nach Bedarf hinzufügen
  • Privat: Ihr Code und Ihre Daten bleiben auf Ihrer Infrastruktur, sofern Ihre Workflows sie nicht an externe Dienste senden

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 selbst betriebene Installationen betreffen.

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

Nächste Schritte


Über tva

tva übernimmt das umfassende Infrastrukturmanagement für Datenbanksysteme, Cloud-Umgebungen und globale Lieferketten. Unser methodischer Ansatz verbindet strenge Sicherheitsprotokolle mit Leistungsoptimierung. Unsere strategische Beratung ermöglicht die präzise Koordination digitaler Fähigkeiten und physischer Ressourcen. Dabei halten wir in allen Kundenprojekten höchste Standards für betriebliche Exzellenz und Compliance ein.

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

Weiterführende Beiträge

Weiterführende Beiträge