CreaRack-SL

Footgun Dokploy: env vars en UI que no llegan al container

El problema

Dokploy no hace merge de variables de entorno entre su panel UI y el compose.yml/compose.prod.yml. Si una variable está configurada en el panel de Dokploy pero no aparece listada en el bloque environment: del servicio en el compose, la variable nunca llega al container en tiempo de ejecución.

Esto es contrario a la intuición de quien viene de otros PaaS (Railway, Render, Fly.io) donde las env vars del panel se inyectan independientemente del compose.

Síntoma clásico

El container arranca sin error. Los logs no muestran nada sospechoso. El código Python lee la variable con os.environ.get("MI_VAR", "default") y silenciosamente usa el default — aunque en el panel de Dokploy la variable esté correctamente seteada con otro valor.

El bug es especialmente traicionero porque:

  1. No hay warning ni error en los logs de Dokploy.
  2. El panel muestra la variable como “configurada”.
  3. El comportamiento es funcional (usa el default), solo incorrecto.

Incidente real: s48 OpenRouter provider order

Detectado el 2026-05-03 durante la primera prueba PROD del switch de Auto-Plan a OpenRouter:

  • Variable OPENROUTER_PROVIDER_ORDER=DekaLLM,Novita,Ionstream ✅ configurada en panel Dokploy.
  • Variable no listada en compose.yml / compose.prod.yml ❌.
  • Resultado: el driver leyó siempre el default hardcoded y OpenRouter ruteó por disponibilidad → sirvió Ionstream (calidad ~20%) en vez de DekaLLM (calidad 100%).
  • Fix: 34895cd — añadida OPENROUTER_PROVIDER_ORDER=${OPENROUTER_PROVIDER_ORDER:-} a los 3 servicios afectados (web dev, web prod, worker prod).

La regla

Toda variable de entorno que deba llegar a un container en Dokploy DEBE aparecer explícitamente en el bloque environment: del servicio correspondiente en compose.yml o compose.prod.yml.

Patrón recomendado

services:
  web:
    environment:
      # Variables con valor literal (siempre presentes)
      - DJANGO_SETTINGS_MODULE=core.settings.production

      # Variables desde el host/Dokploy (con fallback vacío)
      - MI_VARIABLE=${MI_VARIABLE:-}

      # Variables con fallback no vacío (default explícito)
      - OTRA_VARIABLE=${OTRA_VARIABLE:-valor_default}

El patrón ${VAR:-} expone la variable con string vacío como fallback cuando no está seteada en el host. Esto es diferente a omitirla: al estar listada, Dokploy/Docker la incluye en el entorno del proceso.

Servicios afectados en CreaRack Pro

Los servicios que requieren variables de entorno controlables desde Dokploy son:

ServicioComposeVariables críticas
web (dev)compose.ymlOPENROUTER_API_KEY, OPENROUTER_PROVIDER_ORDER, GEMINI_API_KEY, AUTOPLAN_PROVIDER
web (prod)compose.prod.ymlÍdem + VICTORIAMETRICS_URL, MIB_CACHE_DIR
worker (prod)compose.prod.ymlOPENROUTER_API_KEY, OPENROUTER_PROVIDER_ORDER, GEMINI_API_KEY, AUTOPLAN_PROVIDER, EDGE_AI_PROVIDER

Checklist al añadir una nueva env var

  • ¿Está en compose.yml → bloque environment: del servicio que la usa?
  • ¿Está en compose.prod.yml → bloque environment: de todos los servicios que la usan (web + worker si aplica)?
  • ¿Se ha documentado en CLAUDE.md (sección de env vars) si es una variable de configuración de comportamiento?
  • ¿Tiene un fallback razonable (${VAR:-default}) para entornos locales sin .env?

Por qué pasa esto en Dokploy

Dokploy gestiona env vars en su BD interna y las pasa al docker-compose up como variables del entorno del proceso que ejecuta Docker. Docker Compose solo propaga al container las variables que menciona explícitamente en el bloque environment: (interpolación ${VAR}). Las variables del entorno del proceso anfitrión que no están referenciadas en el compose nunca se inyectan — es comportamiento estándar de Docker Compose, no un bug de Dokploy.

Véase también

  • [[entity—blueprints—service—openrouter-driver]]
  • [[feature—blueprints—autoplan]]
  • [[runbook—infra—rotate-mcp-token]]