tva
← Approfondimenti

Self-hosting di Windmill nel 2026: worker, PostgreSQL, isolamento e aggiornamenti sicuri

Un approfondimento aggiornato e orientato alla produzione che traduce la documentazione dei fornitori in controlli operativi, decisioni di migrazione e criteri di rilascio verificabili.

Cosa è cambiato nel 2026

Torniamo su questo tema perché i confini operativi sono cambiati. I principi di fondo restano validi, ma le versioni attuali rendono alcune scorciatoie del passato incomplete o rischiose. Questo approfondimento parte dalla documentazione ufficiale disponibile al 14 luglio 2026, distingue i fatti dalle scelte locali e tratta ogni modifica di configurazione come un intervento controllato in produzione.

Fonti primarie aggiornate

Come utilizziamo questo aggiornamento

Leggi prima le fonti, registra le versioni realmente distribuite e definisci il risultato osservabile prima di modificare qualsiasi impostazione. Prova il più piccolo intervento reversibile in un ambiente rappresentativo. Un comando eseguito con successo non è un criterio di accettazione: lo sono lo stato del servizio, l’integrità dei dati, la latenza, i confini di sicurezza e il tempo necessario al rollback. La sequenza diagnostica ancora utile dell’articolo precedente viene mantenuta come base operativa; gli esempi legati a una versione devono comunque essere verificati nella documentazione corrente.

Prima del rilascio registriamo le differenze di configurazione, un backup o un’istantanea di cui sia già stato verificato almeno una volta il ripristino e i comandi necessari per annullare l’intervento. Una persona osserva la prima finestra di produzione e un’altra autorizza l’escalation se gli indicatori concordati si muovono nella direzione sbagliata. Gli avvisi devono descrivere il rischio visibile per l’utente, non soltanto il componente che li ha emessi. Durante la finestra di verifica confrontiamo tassi di errore, lunghezza delle code, saturazione delle risorse, latenza di elaborazione e completezza dei dati con il riferimento iniziale concordato. Esaminiamo medie e code della distribuzione, perché una media stabile può nascondere errori che colpiscono una quota piccola ma importante del lavoro. La modifica viene chiusa solo dopo il completamento di job differiti, nuovi tentativi, attività pianificate ed esportazioni verso i sistemi a valle. Ogni azione manuale di ripristino viene documentata: se manca dal manuale operativo, il manuale non è ancora completo. Questa disciplina di rilascio produce evidenze riutilizzabili al prossimo aggiornamento, evitando al team di dover riscoprire le stesse dipendenze.

Base operativa

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)

# Create environment file
cat > /opt/windmill-pizza/.env << EOF
# Windmill Image Version (pin a release; change it deliberately when you update)
WM_IMAGE=ghcr.io/windmill-labs/windmill:1.767.0

# 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

# The file holds the database password: make it readable by its owner only
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'
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, il risultato può contenere +, / e =. All’interno di DATABASE_URL, questi caratteri devono essere codificati tramite codifica percentuale; se non vengono codificati, possono compromettere l’analisi dell’URL e manifestarsi come errori di autenticazione PostgreSQL. Le password esadecimali evitano del tutto questo passaggio di codifica.

Esempio di password problematica:

# Unless percent-encoded, the "/" in this password breaks DATABASE_URL:
PASSWORD="305t6m9KrChkvbyN/FLEYQ6pqAGlApn9rbJPH3D5y9g="

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 ruoli windmill_admin e windmill_user richiesti dalle migrazioni di Windmill (vedi la documentazione sul self-hosting di Windmill)
  • Persistenza dei volumi: PostgreSQL ignora le variabili d’ambiente POSTGRES_PASSWORD quando i volumi dati esistenti contengono credenziali diverse
  • Formato dell’URL: Includi ?sslmode=disable nell’URL del database quando quest’ultimo è 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: La reimpostazione del database elimina tutti i dati di Windmill. Eseguila solo su una nuova installazione o dopo un backup verificato.

# WARNING: this deletes all Windmill data (fresh install or verified backup only)
cd /opt/windmill-pizza

# Stop containers
docker compose down --volumes

# Remove old data
rm -rf /opt/windmill-pizza/postgres-data/*

# Regenerate hex password and write it to both variables
NEW_PASSWORD=$(openssl rand -hex 16)
sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$NEW_PASSWORD/" .env
sed -i "s|^DATABASE_URL=postgresql://postgres:[^@]*@|DATABASE_URL=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
  • 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
umask 077

# docker compose needs the project directory, also when run from cron
cd /opt/windmill-pizza

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE=/opt/backups/windmill_pizza_${DATE}.sql
mkdir -p /opt/backups

if ! docker compose exec -T windmill-db pg_dump -U postgres windmill_pizza > "$BACKUP_FILE" || [ ! -s "$BACKUP_FILE" ]; then
  rm -f "$BACKUP_FILE"
  echo "Backup FAILED" >&2
  exit 1
fi
echo "Backup created: $BACKUP_FILE"
EOF

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

Configura il monitoraggio

cd /opt/windmill-pizza

# 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
set -euo pipefail
cd /opt/windmill-pizza

# Back up first; stop here if the backup fails
./backup.sh

# Pull and start the images set in .env (raise WM_IMAGE there to update Windmill)
docker compose pull
docker compose up -d
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
- [email protected]
# Only if your mail server requires authentication:
# - SMTP_USERNAME=...
# - SMTP_PASSWORD=...

Più istanze Windmill

Per i team che richiedono ambienti isolati:

# Create second instance from the configuration files only (not the data)
mkdir -p /opt/windmill-pasta/{postgres-data,windmill-data,lsp-cache}
cp /opt/windmill-pizza/{.env,docker-compose.yml,backup.sh,update.sh} /opt/windmill-pasta/
chmod 600 /opt/windmill-pasta/.env
cd /opt/windmill-pasta

# Update names, paths and domain
sed -i 's/pizza/pasta/g' .env docker-compose.yml backup.sh update.sh
sed -i 's/windmill.yourdomain.com/pasta.yourdomain.com/g' .env docker-compose.yml

# Generate new password and write it to both variables
NEW_PASSWORD=$(openssl rand -hex 16)
sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$NEW_PASSWORD/" .env
sed -i "s|^DATABASE_URL=postgresql://postgres:[^@]*@|DATABASE_URL=postgresql://postgres:$NEW_PASSWORD@|" .env

# Start the new instance
docker compose up -d

Considerazioni sulla sicurezza

Isolamento della rete

  • PostgreSQL è raggiungibile solo dai container sulla sua rete Docker; se questa rete è condivisa con il reverse proxy e altri servizi, 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 job 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

cd /opt/windmill-pizza

# Container status
docker compose ps

# Resource usage
docker stats --no-stream

# Log analysis
docker compose logs | grep -i error

Manutenzione mensile

# Back up and update containers (update.sh runs backup.sh first)
cd /opt/windmill-pizza
./update.sh

# Clean unused images, containers and networks
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: oltre 250 $ all’anno quando due o più sviluppatori hanno bisogno 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

cd /opt/windmill-pizza

# 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 (under services: in docker-compose.yml)
windmill-worker-2:
  image: ${WM_IMAGE}
  container_name: windmill-pizza-worker-2
  restart: unless-stopped
  environment:
    - DATABASE_URL=${DATABASE_URL}
    - MODE=worker
    - WORKER_GROUP=heavy
  networks:
    - proxy
  depends_on:
    windmill-db:
      condition: service_healthy
  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 passate e conservate in modo persistente le credenziali PostgreSQL e usare password con soli caratteri esadecimali, evitando i problemi di codifica degli 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
  • Scalabilità: È facile aggiungere worker e risorse secondo le necessità
  • Riservatezza: Il codice e i dati rimangono 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.

Dalla configurazione alla decisione operativa

La domanda pratica non è se una piattaforma possa essere configurata. È se il team sappia chiarire le responsabilità, rilevare gli scostamenti, ripristinare il servizio senza improvvisare e dimostrare che la modifica abbia migliorato il risultato previsto. Per questo associamo ogni configurazione a un responsabile, un riferimento iniziale, un percorso di rollback e una finestra di verifica. Una correzione isolata diventa così una capacità operativa. Il registro di produzione dovrebbe includere il motivo della modifica, le evidenze esaminate, l’ambito esatto e la persona autorizzata a interromperla o annullarla. Dopo il rilascio, confronta gli indicatori concordati con il riferimento iniziale e conserva il risultato insieme alla registrazione della modifica. Se il miglioramento atteso non si verifica, il rollback è un esito valido, non un fallimento. Questa disciplina conta più di qualsiasi singolo valore di configurazione. La stessa registrazione offre a chi subentra nella gestione un punto di partenza affidabile e rende le ottimizzazioni successive decisioni basate su misurazioni anziché un nuovo ciclo di ipotesi.

Approfondimenti correlati

Per approfondire