tva
← Artículos

Autoalojar Windmill en 2026: workers, PostgreSQL, aislamiento y actualizaciones seguras

Un artículo de seguimiento actualizado y orientado a producción que convierte la documentación del proveedor en controles operativos, decisiones de migración y criterios de despliegue verificables.

Qué ha cambiado en 2026

Retomamos este tema porque los límites operativos han cambiado. Los principios duraderos siguen siendo útiles, pero las versiones actuales hacen que algunos atajos anteriores sean incompletos o arriesgados. Este seguimiento parte de la documentación oficial disponible el 14 de julio de 2026, separa los hechos de las decisiones locales y trata cada cambio de configuración como una intervención controlada en producción.

Fuentes primarias actuales

Cómo utilizar esta actualización

Consulte primero las fuentes, registre las versiones realmente desplegadas y defina el resultado observable antes de cambiar un ajuste. Pruebe la intervención reversible más pequeña en un entorno representativo. Que un comando se ejecute con éxito no es el criterio de aceptación: lo son el estado del servicio, la integridad de los datos, la latencia, los límites de seguridad y el tiempo de reversión. Conservamos a continuación las secuencias de diagnóstico útiles de la guía anterior como base operativa; los ejemplos que dependen de una versión deben contrastarse con la documentación vigente.

Antes del despliegue, guarde las diferencias de configuración, una copia de seguridad o instantánea que se haya restaurado al menos una vez y los comandos necesarios para revertir la intervención. Asigne una persona para observar la primera ventana de producción y otra para autorizar el escalamiento si los indicadores previstos evolucionan en la dirección equivocada. Las alertas deben describir el riesgo visible para el usuario, no solo el componente que las emite. Durante el período de verificación del resultado registrado, compare las tasas de error, la profundidad de las colas, la saturación de recursos, la latencia de procesamiento y la completitud de los datos con la línea de base acordada. Revise tanto los promedios como el comportamiento en los extremos de la distribución, porque un promedio estable puede ocultar fallos que afectan a una parte pequeña pero importante del trabajo. Cierre el cambio solo cuando hayan terminado los trabajos diferidos, los reintentos, las tareas programadas y las exportaciones a sistemas posteriores. Registre cualquier acción manual realizada durante la recuperación: un paso de rescate sin documentar demuestra que el manual de operaciones aún está incompleto. Esta disciplina de despliegue genera evidencias reutilizables en la siguiente actualización, en lugar de obligar al equipo a redescubrir las mismas dependencias.

Base operativa

Las plataformas de automatización de flujos de trabajo son esenciales para los equipos de desarrollo modernos, pero las soluciones en la nube como Windmill Cloud pueden resultar costosas a medida que crece el uso. Le mostraremos cómo configurar su propia instancia de Windmill en Ubuntu con Docker Compose e integración con Traefik, superando los problemas críticos de autenticación de PostgreSQL que pueden hacer fallar su instalación.

Qué va a configurar

Al finalizar este tutorial, tendrá:

  • Instalación de Windmill completamente funcional con HTTPS
  • Certificados SSL automáticos mediante Let's Encrypt a través de Traefik
  • Base de datos PostgreSQL lista para producción con autenticación adecuada
  • Configuración de workers con uso optimizado de recursos
  • Integrada con la infraestructura Docker existente
  • Configuración preparada para automatizar flujos de trabajo profesionales en producción

Costo mensual: desde 5,99 EUR sin IVA, con una dirección IPv4 primaria incluida (Hetzner CX23, 4 GB RAM, a octubre de 2026) + costos de dominio — la misma infraestructura puede ejecutar varias herramientas de automatización

Requisitos previos

  • Servidor Ubuntu 24.04 LTS con Docker y Docker Compose instalados
  • Proxy inverso Traefik ya configurado (consulte nuestra guía de configuración de n8n para la configuración de Traefik)
  • Nombre de dominio que apunte a la IP de su servidor
  • Se recomiendan al menos 4 GB de RAM y 2 vCPU
  • Acceso SSH y conocimientos básicos de línea de comandos

Qué es Windmill

Windmill es un motor de flujos de trabajo de código abierto que proporciona:

  • Editor visual de flujos de trabajo con soporte para TypeScript/Python/Go
  • Programación de tareas y gestión de la ejecución
  • Capacidades de integración con API
  • Funciones de colaboración en equipo
  • Autoalojable, con ejecuciones ilimitadas en la Community Edition gratuita

A diferencia del enfoque basado en nodos de n8n, Windmill se centra en flujos de trabajo orientados al código con un potente entorno de desarrollo.

Paso 1: preparación del servidor y estructura de directorios

Primero prepararemos el entorno del servidor. Usaremos nombres de comidas para las instancias de Windmill con el fin de evitar conflictos:

# 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

Convención de nombres: use nombres sencillos de comidas para las distintas instancias de Windmill:

  • Primera instancia: pizza
  • Instancias adicionales: pasta, salad, soup, burger, etc.
  • Esto evita conflictos y facilita la gestión

Paso 2: configuración del entorno

Cree un archivo de entorno seguro con credenciales adecuadas:

# 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

Crítico: Reemplace windmill.yourdomain.com con su dominio real.

Paso 3: configuración de Docker Compose

Cree la configuración principal de 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: Actualice el dominio en las etiquetas de Traefik para que coincida con su configuración.

Paso 4: el problema de las contraseñas de PostgreSQL (problema crítico)

En este punto falla la mayoría de las instalaciones de Windmill; identificar la causa raíz exigió una investigación considerable:

El problema: caracteres especiales en las contraseñas

Al usar openssl rand -base64 32 para generar contraseñas, el resultado puede contener +, / y =. Dentro de DATABASE_URL, estos caracteres deben codificarse con codificación porcentual; si no se codifican, pueden provocar errores al analizar la URL que se manifiesten como fallos de autenticación de PostgreSQL. Las contraseñas hexadecimales evitan por completo este paso de codificación.

Ejemplo de una contraseña problemática:

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

La solución: contraseñas exclusivamente hexadecimales

Use contraseñas compuestas únicamente por caracteres hexadecimales, sin caracteres especiales:

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

Problemas adicionales de configuración de PostgreSQL

  • Configuración de usuario: Use el superusuario postgres, como hace la configuración de ejemplo de Windmill. Un usuario personalizado solo funciona después de que se le asignen los roles windmill_admin y windmill_user que requieren las migraciones de Windmill (consulte la documentación de autoalojamiento de Windmill)
  • Persistencia de volúmenes: PostgreSQL ignora las variables de entorno POSTGRES_PASSWORD cuando los volúmenes de datos existentes contienen credenciales diferentes
  • Formato de URL: Incluya ?sslmode=disable en la URL de la base de datos cuando esta solo sea accesible a través de la red interna de Docker, como en la configuración de ejemplo de Windmill; use un modo SSL como require para las bases de datos a las que se acceda a través de otras redes

Paso 5: instalación e inicio

Ahora instalaremos Windmill con la configuración corregida:

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

Debería ver un resultado como este:

NAME                    STATUS                    PORTS
windmill-pizza-db       Up (healthy)              5432/tcp
windmill-pizza-server   Up                        8000/tcp
windmill-pizza-worker   Up                        8000/tcp

Paso 6: resolución de problemas comunes

Problema 1: fallos de autenticación de PostgreSQL

Síntomas:

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

Solución: Restablecer la base de datos elimina todos los datos de Windmill. Hágalo solo en una instalación nueva o después de una copia de seguridad verificada.

# 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: el contenedor no inicia

Síntomas:

  • El contenedor termina inmediatamente
  • Errores de asignación de recursos

Solución:

# Check container logs
docker logs windmill-pizza-server
docker logs windmill-pizza-db

# Check system resources
docker stats
free -h

Problema 3: problemas con certificados SSL

Síntomas:

  • HTTPS no funciona
  • Errores de certificado

Solución:

# Check Traefik logs
docker logs traefik

# Verify DNS resolution
nslookup windmill.yourdomain.com

# Restart Traefik if needed
docker restart traefik

Paso 7: acceso y configuración inicial

Una vez completada la instalación:

  • Acceda a Windmill: https://windmill.yourdomain.com
  • Credenciales predeterminadas:

Correo electrónico: [email protected]

  • Contraseña: changeme

Cambie la contraseña de administrador

  • Configure la URL base
  • Configure las cuentas de usuario

Paso 8: optimización de recursos

Asignación de memoria (para un servidor de 8 GB)

Nuestra configuración asigna recursos de manera eficiente:

  • Servidor de Windmill: ~800 MB
  • Worker de Windmill: 2 GB (limitado)
  • PostgreSQL: ~500 MB
  • Reserva del sistema: ~4,7 GB

Asignación de CPU (para un servidor de 4 vCPU)

  • Worker: 1 vCPU (limitado)
  • Otros servicios: 3 vCPU (compartidos)

Regla de escalado: 1 worker por vCPU, con 1-2 GB de RAM cada uno

Paso 9: refuerzo de la seguridad para producción

Crear script de copia de seguridad

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

Configurar monitoreo

cd /opt/windmill-pizza

# Monitor container health
docker compose ps

# Check resource usage
docker stats

# Monitor logs
docker compose logs -f windmill-server

Configurar actualizaciones automatizadas

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

Paso 10: configuración avanzada

Integración con SMTP existente

Si tiene un servidor de correo (como el de nuestra configuración de n8n), intégrelo:

# 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=...

Varias instancias de Windmill

Para equipos que requieren entornos aislados:

# 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

Consideraciones de seguridad

Aislamiento de red

  • PostgreSQL solo es accesible desde contenedores de su red de Docker; si esa red se comparte con el proxy inverso y otros servicios, use una red interna separada para un aislamiento más estricto
  • Sin puertos de base de datos externos expuestos
  • Terminación HTTPS a nivel de Traefik

Límites de recursos

  • Los contenedores de workers tienen límites de CPU y memoria
  • Los límites de recursos reducen el impacto de los trabajos fuera de control y de los intentos de agotamiento de recursos
  • Configurable según la capacidad del servidor

Seguridad SSL

  • Certificados automáticos de Let's Encrypt
  • Redirecciones de HTTP a HTTPS
  • Configuración TLS moderna

Monitoreo y mantenimiento

Comprobaciones semanales de estado

cd /opt/windmill-pizza

# Container status
docker compose ps

# Resource usage
docker stats --no-stream

# Log analysis
docker compose logs | grep -i error

Mantenimiento mensual

# 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

Desglose de costos y comparación

Costos mensuales

Configuración autoalojada:

  • Hetzner CX23 (4 GB RAM): 5,99 EUR/mes sin IVA, con una dirección IPv4 primaria incluida (a octubre de 2026)
  • Costos de dominio: ~1 EUR/mes
  • Total: ~7 EUR/mes sin IVA

Comparación con Windmill Cloud:

  • Cloud: $20/mes por puesto de desarrollador, $10/mes por operador (a octubre de 2026)
  • Ahorro: más de $250 anuales cuando dos o más desarrolladores necesitan puestos

Ventajas de rendimiento

Ventajas del autoalojamiento:

  • Ejecuciones de flujos de trabajo ilimitadas
  • Sin límites externos de solicitudes
  • Control total de los datos
  • Integraciones personalizadas
  • Flexibilidad de escalado de recursos

Referencia de resolución de problemas

Diagnóstico rápido

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)"

Patrones de error comunes

  • "password authentication failed" — Use contraseñas hexadecimales; limpie los volúmenes solo después de una copia de seguridad o en una instalación nueva
  • "connection refused" — Verifique la configuración de red
  • "certificate errors" — Verifique DNS y la configuración de Traefik
  • "out of memory" — Ajuste los límites de recursos del worker

Escalar su infraestructura de Windmill

Escalado horizontal

Para entornos de alto volumen:

# 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

Escalado vertical

Actualice los recursos del servidor (precios de Hetzner sin IVA, con una dirección IPv4 primaria incluida a octubre de 2026):

  • CX33 (8 GB RAM): 8,99 EUR/mes para cargas de trabajo exigentes
  • CX43 (16 GB RAM): 16,49 EUR/mes para uso empresarial

Integración con infraestructura existente

Uso junto con n8n

Si ya está ejecutando n8n (de nuestros tutoriales anteriores):

  • Windmill maneja flujos de trabajo orientados al código
  • n8n maneja automatizaciones visuales y simples
  • Ambos comparten el mismo proxy Traefik
  • Bases de datos separadas previenen conflictos

Servicios compartidos

Aproveche la infraestructura existente:

  • Traefik: gestiona SSL para todos los servicios
  • Servidor de correo: SMTP compartido para notificaciones
  • Monitoreo: registros y métricas unificados
  • Copias de seguridad: Estrategia centralizada de copias de seguridad

Conclusión

El autoalojamiento de Windmill proporciona automatización de flujos de trabajo de nivel empresarial a una fracción de los costos de alojamiento en la nube. La clave del éxito es comprender cómo se transmiten y almacenan de forma persistente las credenciales de PostgreSQL y usar contraseñas compuestas únicamente por caracteres hexadecimales para evitar problemas de codificación de URL que pueden hacer fallar las instalaciones.

Beneficios clave de esta configuración

  • Rentable: Ahorre cientos al año en comparación con las soluciones en la nube
  • Listo para producción: Maneja cargas de trabajo empresariales de manera fiable
  • Seguro: HTTPS, ningún puerto de base de datos expuesto y límites de recursos
  • Escalable: Fácil de agregar workers y recursos según sea necesario
  • Privado: Su código y datos permanecen en su infraestructura, salvo que sus flujos de trabajo los envíen a servicios externos

Esta configuración ha sido probada en entornos de producción y proporciona la fiabilidad necesaria para la automatización de flujos de trabajo críticos para el negocio. Los pasos de resolución de problemas abordan problemas reales encontrados durante el despliegue, particularmente los problemas de autenticación de PostgreSQL que afectan a muchas instalaciones autoalojadas.

Para requisitos complejos de flujos de trabajo o implementaciones empresariales, considere recurrir a asesoría profesional para optimizar su caso de uso específico y garantizar una asignación óptima de recursos.

Próximos pasos

  • Explore las técnicas de resolución de problemas de webhooks que se aplican a Windmill
  • Revise la optimización de carga útil para gestionar grandes conjuntos de datos
  • Considere la integración con instalaciones existentes de n8n

Acerca de tva

tva garantiza una gestión integral de la infraestructura de bases de datos, los entornos en la nube y las cadenas de suministro globales. Nuestro enfoque metódico combina protocolos de seguridad rigurosos con optimización del rendimiento, mientras que los servicios de asesoría estratégica permiten la coordinación precisa tanto de las capacidades digitales como de los activos físicos, manteniendo los más altos estándares de excelencia operativa y cumplimiento normativo en todos los proyectos.

Visite tva.sg para más información sobre nuestros servicios y tutoriales adicionales de automatización.

De la configuración a una decisión operativa

La cuestión práctica no es si una plataforma se puede configurar, sino si el equipo puede explicar quién es responsable, detectar desviaciones, recuperar el servicio sin improvisar y demostrar que el cambio mejoró el resultado previsto. Por eso asociamos cada configuración con un responsable, una línea de base, una ruta de reversión y un período de verificación del resultado registrado. Así, una corrección puntual se convierte en una capacidad operativa. El registro de producción debe incluir el motivo del cambio, las evidencias revisadas, el alcance exacto y la persona autorizada para detenerlo o revertirlo. Después del despliegue, compare los indicadores acordados con la línea de base y conserve el resultado junto con el registro del cambio. Si no se observa la mejora esperada, la reversión es un resultado válido, no un fracaso. Esta disciplina importa más que cualquier valor de configuración individual. El mismo registro ofrece al siguiente operador un punto de partida fiable y hace que la optimización posterior sea una decisión basada en mediciones, en lugar de otra ronda de conjeturas.

Artículos relacionados

Artículos relacionados