Self-hosting di Windmill su Ubuntu: tutorial completo di configurazione Docker e risoluzione dei problemi PostgreSQL
Le piattaforme di automazione dei flussi di lavoro sono essenziali per i team di sviluppo moderni, ma le soluzioni cloud come Windmill Cloud possono diventare costose con l’aumento dell’utilizzo. Ti mostreremo come configurare la tua istanza Windmill su Ubuntu con Docker Compose e l’integrazione con Traefik, superando i problemi critici di autenticazione PostgreSQL che possono compromettere l’installazione.
Cosa realizzerai
Al termine di questo tutorial avrai:
- ✅ Un’installazione Windmill pienamente funzionante con HTTPS
- ✅ Certificati SSL automatici tramite Let’s Encrypt e Traefik
- ✅ Un database PostgreSQL pronto per la produzione con autenticazione corretta
- ✅ Una configurazione dei worker ottimizzata per le risorse disponibili
- ✅ Integrazione con l’infrastruttura Docker esistente
- ✅ Una configurazione pronta per la produzione per l’automazione professionale dei flussi di lavoro
Costo mensile: da 5,99 € IVA esclusa, con un indirizzo IPv4 primario incluso (Hetzner CX23, 4 GB RAM, a ottobre 2026) + costo del dominio – la stessa infrastruttura può gestire più strumenti di automazione
Prerequisiti
- Server Ubuntu 24.04 LTS con Docker e Docker Compose installati
- Reverse proxy Traefik già configurato (consulta la nostra guida alla configurazione di n8n per configurare Traefik)
- Un nome di dominio che punti all’IP del server
- Si consigliano almeno 4GB di RAM e 2 vCPU
- Accesso SSH e conoscenza di base della riga di comando
Come funziona Windmill
Windmill è un motore open source per i flussi di lavoro che offre:
- Editor visuale dei flussi di lavoro con supporto per TypeScript/Python/Go
- Pianificazione dei job e gestione dell’esecuzione
- Funzionalità di integrazione API
- Funzionalità di collaborazione in team
- Self-hosting, con esecuzioni illimitate nella Community Edition gratuita
A differenza dell’approccio a nodi di n8n, Windmill punta su flussi di lavoro basati sul codice, con un potente ambiente di sviluppo.
Passaggio 1: preparazione del server e struttura delle directory
Per prima cosa prepariamo l’ambiente del server. Useremo nomi di alimenti per le istanze Windmill, così da evitare conflitti:
# 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
Convenzione di denominazione: Usa semplici nomi di alimenti per distinguere più istanze Windmill:
- Prima istanza:
pizza - Istanze aggiuntive:
pasta,salad,soup,burger, ecc. - Questo evita conflitti e semplifica la gestione
Passaggio 2: configurazione dell’ambiente
Crea un file delle variabili d’ambiente sicuro con le credenziali corrette:
# 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
Attenzione: Sostituisci windmill.yourdomain.com con il tuo dominio effettivo!
Passaggio 3: configurazione di Docker Compose
Crea la configurazione principale di Docker Compose:
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
Importante: Aggiorna il dominio nelle etichette Traefik in modo che corrisponda alla tua configurazione!
Passaggio 4: il problema della password PostgreSQL (problema critico)
È qui che fallisce la maggior parte delle installazioni Windmill; individuare la causa ha richiesto un lungo lavoro di diagnosi:
Il problema: caratteri speciali nelle password
Quando usi openssl rand -base64 32 per generare password, l’output può contenere +, / e =. In DATABASE_URL, questi caratteri devono essere codificati con la codifica percentuale; se non lo sono, possono compromettere l’interpretazione dell’URL e manifestarsi come errori di autenticazione PostgreSQL. Le password esadecimali evitano del tutto questo passaggio di codifica.
Esempio di password problematica:
# This WILL cause authentication failures:
PASSWORD="305t6m9KrC/kvbyNEF+EYQ6pqAGlApn9rbJPH3D5y9g="
La soluzione: password con soli caratteri esadecimali
Usa password con soli caratteri esadecimali, senza caratteri speciali:
# This WORKS reliably:
PASSWORD=$(openssl rand -hex 16)
# Example result: 5781b14ec0ec1bc184653ffa5e379411
Altri problemi di configurazione PostgreSQL
- Configurazione dell’utente: Usa il superutente
postgres, come nella configurazione di esempio di Windmill. Un utente personalizzato funziona solo dopo aver ricevuto i ruoliwindmill_adminewindmill_userrichiesti dalle migrazioni di Windmill (vedi la documentazione di Windmill sul self-hosting) - Persistenza dei volumi: PostgreSQL ignora le variabili d’ambiente
POSTGRES_PASSWORDquando i volumi dati esistenti contengono credenziali diverse - Formato dell’URL: Includi
?sslmode=disablenell’URL del database quando questo è raggiungibile solo sulla rete Docker interna, come nella configurazione di esempio di Windmill; usa una modalità SSL comerequireper i database raggiunti tramite altre reti
Passaggio 5: installazione e avvio
Ora installiamo Windmill con la configurazione corretta:
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
Dovresti vedere un output simile a questo:
NAME STATUS PORTS
windmill-pizza-db Up (healthy) 5432/tcp
windmill-pizza-server Up 8000/tcp
windmill-pizza-worker Up 8000/tcp
Passaggio 6: risoluzione dei problemi comuni
Problema 1: errori di autenticazione PostgreSQL
Sintomi:
windmill-pizza-server | Error: password authentication failed for user "postgres"
Soluzione: Questa operazione elimina tutti i dati del database di Windmill. Usala solo su una nuova installazione o dopo un backup verificato. I due comandi sed scrivono la nuova password in POSTGRES_PASSWORD e in 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
Problema 2: il container non si avvia
Sintomi:
- Il container termina immediatamente
- Errori di allocazione delle risorse
Soluzione:
# Check container logs
docker logs windmill-pizza-server
docker logs windmill-pizza-db
# Check system resources
docker stats
free -h
Problema 3: certificati SSL
Sintomi:
- HTTPS non funziona
- Errori dei certificati
Soluzione:
# Check Traefik logs
docker logs traefik
# Verify DNS resolution
nslookup windmill.yourdomain.com
# Restart Traefik if needed
docker restart traefik
Passaggio 7: accesso e configurazione iniziale
Una volta completata l’installazione:
- Accedi a Windmill: https://windmill.yourdomain.com
- Credenziali predefinite:
- Email:
[email protected] - Password:
changeme
- Email:
- Completa la configurazione:
- Cambia la password dell’amministratore
- Configura l’URL di base
- Configura gli account utente
Passaggio 8: ottimizzazione delle risorse
Allocazione della memoria (per un server da 8GB)
La nostra configurazione alloca le risorse in modo efficiente:
- Server Windmill: ~800MB
- Worker Windmill: 2GB (limite)
- PostgreSQL: ~500MB
- Riserva per il sistema: ~4.7GB
Allocazione della CPU (per un server con 4 vCPU)
- Worker: 1 vCPU (limite)
- Altri servizi: 3 vCPU (condivise)
Regola di scalabilità: 1 worker per vCPU con 1-2GB di RAM ciascuno
Passaggio 9: rafforzamento della sicurezza in produzione
Crea uno script di backup
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
Configura il monitoraggio
# Monitor container health
docker compose ps
# Check resource usage
docker stats
# Monitor logs
docker compose logs -f windmill-server
Configura gli aggiornamenti automatici
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
Passaggio 10: configurazione avanzata
Integrazione con il servizio SMTP esistente
Se hai un mailserver (come quello della nostra configurazione n8n), integralo:
# Add to docker-compose.yml environment for windmill-server:
- SMTP_HOST=mailserver
- SMTP_PORT=25
- SMTP_USERNAME=
- SMTP_PASSWORD=
- [email protected]
Più istanze Windmill
Per i team che richiedono ambienti isolati, la seconda istanza riceve directory dati vuote, un database e una password propri:
# 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
Considerazioni sulla sicurezza
Isolamento della rete
- PostgreSQL è raggiungibile solo dai container sulla rete Docker condivisa
proxy; usa una rete interna separata per un isolamento più rigoroso - Nessuna porta del database è esposta all’esterno
- Terminazione HTTPS a livello di Traefik
Limiti delle risorse
- I container dei worker hanno limiti di CPU e memoria
- I limiti delle risorse riducono l’impatto dei processi fuori controllo e dei tentativi di esaurimento delle risorse
- Configurabile in base alla capacità del server
Sicurezza SSL
- Certificati Let’s Encrypt automatici
- Reindirizzamenti da HTTP a HTTPS
- Configurazione TLS moderna
Monitoraggio e manutenzione
Controlli settimanali dello stato dei servizi
# Container status
docker compose ps
# Resource usage
docker stats --no-stream
# Log analysis
docker compose logs | grep -i error
Manutenzione mensile
# Backup database first
cd /opt/windmill-pizza
./backup.sh
# Update containers
./update.sh
# Clean old data
docker system prune -f
Dettaglio e confronto dei costi
Costi mensili
Configurazione sulla propria infrastruttura:
- Hetzner CX23 (4 GB RAM): 5,99 €/mese IVA esclusa, con un indirizzo IPv4 primario incluso (a ottobre 2026)
- Costo del dominio: ~€1/mese
- Totale: ~7 €/mese IVA esclusa
Confronto con Windmill Cloud:
- Cloud: 20 $/mese per postazione sviluppatore, 10 $/mese per operatore (a ottobre 2026)
- Risparmio: 250 $+ all’anno quando due o più sviluppatori necessitano di una postazione
Vantaggi in termini di prestazioni
Vantaggi del self-hosting:
- Esecuzioni illimitate dei flussi di lavoro
- Nessun limite esterno alla frequenza delle richieste
- Controllo completo dei dati
- Integrazioni personalizzate
- Flessibilità nell’aumento delle risorse
Riferimenti per la risoluzione dei problemi
Diagnostica rapida
# 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)"
Errori comuni
- “password authentication failed” → Usa password esadecimali; svuota i volumi solo dopo un backup o su una nuova installazione
- “connection refused” → Controlla la configurazione di rete
- “certificate errors” → Verifica il DNS e la configurazione di Traefik
- “out of memory” → Regola i limiti delle risorse dei worker
Scalabilità dell’infrastruttura Windmill
Scalabilità orizzontale
Per gli ambienti con volumi elevati:
# 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
Scalabilità verticale
Aumenta le risorse del server (prezzi Hetzner IVA esclusa, con un indirizzo IPv4 primario incluso a ottobre 2026):
- CX33 (8 GB RAM): 8,99 €/mese per carichi di lavoro elevati
- CX43 (16 GB RAM): 16,49 €/mese per l’uso aziendale
Integrazione con l’infrastruttura esistente
Uso insieme a n8n
Se usi già n8n (come nei nostri tutorial precedenti):
- Windmill gestisce flussi di lavoro basati sul codice
- n8n gestisce automazioni semplici e visuali
- Entrambi condividono lo stesso proxy Traefik
- Database separati evitano conflitti
Servizi condivisi
Sfrutta l’infrastruttura esistente:
- Traefik: Gestisce SSL per tutti i servizi
- Mailserver: SMTP condiviso per le notifiche
- Monitoraggio: Log e metriche unificati
- Backup: Strategia di backup centralizzata
Conclusione
Il self-hosting di Windmill offre automazione dei flussi di lavoro di livello aziendale a una frazione del costo dell’hosting cloud. Per riuscirci è essenziale comprendere come vengono trasmesse e conservate le credenziali PostgreSQL e usare password con soli caratteri esadecimali, evitando i problemi di codifica dell’URL che possono compromettere le installazioni.
Vantaggi principali di questa configurazione
- Convenienza: Risparmi centinaia all’anno rispetto alle soluzioni cloud
- Pronta per la produzione: Gestisce i carichi di lavoro aziendali in modo affidabile
- Sicurezza: HTTPS, nessuna porta del database esposta e limiti delle risorse (il montaggio del socket Docker concede comunque al worker accesso a livello di host)
- Scalabilità: È facile aggiungere worker e risorse secondo le necessità
- Riservatezza: Il codice e i dati restano sulla tua infrastruttura, a meno che i tuoi flussi di lavoro non li inviino a servizi esterni
Questa configurazione è stata testata in ambienti di produzione e offre l’affidabilità necessaria per l’automazione dei flussi di lavoro critici per l’azienda. I passaggi di risoluzione dei problemi affrontano difficoltà reali incontrate durante la distribuzione, in particolare i problemi di autenticazione PostgreSQL che interessano molte installazioni sulla propria infrastruttura.
Per flussi di lavoro complessi o distribuzioni aziendali, valuta una consulenza professionale per ottimizzare il tuo caso d’uso specifico e garantire un’allocazione ottimale delle risorse.
Prossimi passi
- Esplora le tecniche di risoluzione dei problemi dei webhook applicabili a Windmill
- Approfondisci l’ottimizzazione del payload per gestire grandi insiemi di dati
- Valuta l’integrazione con le installazioni n8n esistenti
Informazioni su tva
tva assicura una gestione completa dell’infrastruttura di sistemi di database, ambienti cloud e catene di approvvigionamento globali. Il nostro approccio metodico combina rigorosi protocolli di sicurezza con l’ottimizzazione delle prestazioni, mentre i servizi di consulenza strategica consentono di coordinare con precisione sia le capacità digitali sia le risorse fisiche, mantenendo i più elevati standard di eccellenza operativa e conformità in tutti gli incarichi.
Visita tva.sg per maggiori informazioni sui nostri servizi e altri tutorial sull’automazione.
Approfondimenti correlati
Per approfondire
Self-hosting di n8n su Hetzner Cloud: tutorial completo di configurazione Docker
Self-hosting di Windmill nel 2026: worker, PostgreSQL, isolamento e aggiornamenti sicuri
Guida completa al self-hosting di n8n 2025: risolvere gli errori di dimensione dei dati di esecuzione e i problemi dei webhook con Traefik