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,burgerusw. - 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
- Benutzerkonfiguration: Verwenden Sie den Superuser
postgres, wie in der Beispielkonfiguration von Windmill. Ein benutzerdefinierter Benutzer funktioniert erst, nachdem ihm die Rollenwindmill_adminundwindmill_userzugewiesen wurden, die die Migrationen von Windmill benötigen (siehe die Self-Hosting-Dokumentation von Windmill) - Volume-Persistenz: PostgreSQL ignoriert
POSTGRES_PASSWORD-Umgebungsvariablen, wenn bestehende Datenvolumes andere Zugangsdaten enthalten - URL-Format: Fügen Sie
?sslmode=disablein 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 wierequire
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:
- Windmill aufrufen: https://windmill.yourdomain.com
- Standard-Zugangsdaten:
- E-Mail:
[email protected] - Passwort:
changeme
- E-Mail:
- 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
proxyaus 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
- "password authentication failed" – Verwenden Sie Passwörter aus Hexadezimalzeichen; löschen Sie die Volumes nur nach einem Backup oder bei einer Neuinstallation
- "connection refused" – Prüfen Sie die Netzwerkkonfiguration
- "certificate errors" – Prüfen Sie DNS und das Traefik-Setup
- "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
- Erkunden Sie Webhook-Fehlerbehebungstechniken, die auch für Windmill gelten
- Prüfen Sie Payload-Optimierung für den Umgang mit großen Datensätzen
- Erwägen Sie die Integration mit bestehenden n8n-Installationen
Ü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.