Autoalojar Windmill en Ubuntu: tutorial completo de Docker y solución de problemas de PostgreSQL
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, incluida una dirección IPv4 principal (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)
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
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'
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: 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, la salida puede contener +, / y =. En DATABASE_URL, estos caracteres deben codificarse mediante porcentajes; sin codificar, pueden impedir que la URL se interprete correctamente y manifestarse 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:
# This WILL cause authentication failures:
PASSWORD="305t6m9KrC/kvbyNEF+EYQ6pqAGlApn9rbJPH3D5y9g="
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 en la configuración de ejemplo de Windmill. Un usuario personalizado solo funciona después de que se le concedan los roleswindmill_adminywindmill_userque requieren las migraciones de Windmill (consulte la documentación de autoalojamiento de Windmill) - Persistencia de volúmenes: PostgreSQL ignora las variables de entorno
POSTGRES_PASSWORDcuando los volúmenes de datos existentes contienen credenciales diferentes - Formato de URL: Incluya
?sslmode=disableen la URL de la base de datos cuando esta solo sea accesible en la red interna de Docker, como en la configuración de ejemplo de Windmill; use un modo SSL comorequirepara bases de datos a las que se acceda por 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: Esto elimina todos los datos de la base de datos de Windmill. Úselo solo en una instalación nueva o tras una copia de seguridad verificada. Los dos comandos sed escriben la nueva contraseña en POSTGRES_PASSWORD y en 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: 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
- Correo electrónico:
- Complete la configuración:
- 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
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
Configurar monitoreo
# 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
cd /opt/windmill-pizza
docker compose pull
docker compose up -d --force-recreate
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
- SMTP_USERNAME=
- SMTP_PASSWORD=
- [email protected]
Varias instancias de Windmill
Para equipos que requieren entornos aislados, la segunda instancia recibe sus propios directorios de datos vacíos, su propia base de datos y su propia contraseña:
# 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
Consideraciones de seguridad
Aislamiento de red
- PostgreSQL solo es accesible desde contenedores en la red compartida de Docker
proxy; use una red interna independiente 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
# Container status
docker compose ps
# Resource usage
docker stats --no-stream
# Log analysis
docker compose logs | grep -i error
Mantenimiento mensual
# Backup database first
cd /opt/windmill-pizza
./backup.sh
# Update containers
./update.sh
# Clean old data
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, incluida una dirección IPv4 principal (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: $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
# 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; vacíe los volúmenes solo tras 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
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
Escalado vertical
Actualice los recursos del servidor (precios de Hetzner sin IVA, incluida una dirección IPv4 principal 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 se 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 (el montaje del socket de Docker sigue dando al worker acceso a nivel del host)
- 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.