tva
← Approfondimenti

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

  1. Configurazione dell’utente: Usa il superutente postgres, come nella configurazione di esempio di Windmill. Un utente personalizzato funziona solo dopo aver ricevuto i ruoli windmill_admin e windmill_user richiesti dalle migrazioni di Windmill (vedi la documentazione di Windmill sul self-hosting)
  2. Persistenza dei volumi: PostgreSQL ignora le variabili d’ambiente POSTGRES_PASSWORD quando i volumi dati esistenti contengono credenziali diverse
  3. Formato dell’URL: Includi ?sslmode=disable nell’URL del database quando questo è raggiungibile solo sulla rete Docker interna, come nella configurazione di esempio di Windmill; usa una modalità SSL come require per 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:

  1. Accedi a Windmill: https://windmill.yourdomain.com
  2. Credenziali predefinite:
  3. 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

  1. “password authentication failed” → Usa password esadecimali; svuota i volumi solo dopo un backup o su una nuova installazione
  2. “connection refused” → Controlla la configurazione di rete
  3. “certificate errors” → Verifica il DNS e la configurazione di Traefik
  4. “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


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