Las variables de entorno no llegan al contenedor
Cuando las variables de entorno no funcionan en un contenedor, normalmente se debe a uno de cinco motivos: tiempo de compilación frente a tiempo de ejecución, bundling del frontend, comillas, momento del reinicio o ámbito incorrecto. Compruébalos en este orden.
Configuras la variable. El dashboard la muestra. La aplicación dice que es undefined. Las variables de entorno no funcionan en un contenedor es uno de los fallos de configuración más comunes al alojar aplicaciones, y casi siempre se debe a uno de cinco motivos concretos.
Se indican aquí en el orden que permite encontrar el problema más rápido.
1. El tiempo de compilación y el tiempo de ejecución son mundos distintos
Este motivo causa más casos que los otros cuatro juntos, y es el que suele resultar menos intuitivo.
Las variables configuradas en tu servicio existen cuando el contenedor se ejecuta. Todo lo que hace tu Dockerfile ocurre antes, en un entorno independiente. Un paso RUN no puede ver una variable de ejecución porque, en ese momento, todavía no existe ningún proceso en ejecución.
# This is empty during build. Always.
RUN echo $DATABASE_URL
# This is available at runtime, because it is the running process reading it
CMD ["node", "server.js"]
Si realmente necesitas un valor durante la compilación, debes pasarlo como un argumento de compilación —un mecanismo diferente, con propiedades de seguridad distintas—:
ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"
No pases nunca un secreto de esta forma. Los argumentos de compilación quedan registrados en el historial de capas de la imagen. Cualquiera que pueda descargar la imagen podrá leerlos.
2. Las variables del frontend quedan integradas en el bundle, no se leen
Si tu frontend muestra undefined en producción, casi con total seguridad esta es la razón.
Un navegador no tiene entorno. Cuando escribes import.meta.env.VITE_API_URL o process.env.NEXT_PUBLIC_API_URL, el bundler sustituye el valor literal durante la compilación. En el navegador no se hace ninguna consulta: el valor ya se incluyó al compilar.
Esto tiene tres consecuencias que suelen pasar desapercibidas:
- Cambiar la variable no sirve de nada hasta que vuelvas a compilar. El valor antiguo está dentro del archivo JavaScript.
- El prefijo es obligatorio. Vite solo expone
VITE_y Next.js solo exponeNEXT_PUBLIC_. Una variable sin el prefijo se mantiene oculta deliberadamente. - Todo lo que expongas de esta forma es público. Está en un archivo que sirves a cualquiera. No pongas nunca un secreto detrás de
NEXT_PUBLIC_, independientemente de lo que sugiera el nombre.
Por eso tampoco se puede configurar de esta forma una imagen precompilada después de crearla. Si la imagen se compiló en otro lugar con los valores ya integrados, configurar variables en el servicio no cambia nada: las cadenas ya están en el bundle.
3. Las comillas
Los valores con caracteres especiales se alteran de formas que producen errores confusos en lugar de evidentes.
# The shell eats everything after #
dockup env set DB_PASS=p@ss#word my-project/my-api
# Quote it
dockup env set 'DB_PASS=p@ss#word' my-project/my-api
Los caracteres que causan este problema son: # (comentario), $ (expansión), los espacios (separación de argumentos), ! (expansión del historial en bash interactivo) y los saltos de línea, que aparecen en un caso muy habitual: las claves privadas.
Los valores multilínea son el caso más problemático. Si pegas una clave PEM en un campo de una sola línea, llega sin sus saltos de línea y produce un error de análisis que no menciona los saltos de línea. Codifícala en Base64 y descodifícala en la aplicación:
dockup env set "PRIVATE_KEY_B64=$(base64 -i key.pem)" my-project/my-api
4. No reiniciaste
Los procesos leen las variables de entorno cuando se inician. Cambiarlas afecta al siguiente proceso, no al que se está ejecutando.
La mayoría de las plataformas resuelve esto volviendo a desplegar automáticamente cuando cambia la configuración, pero no todas lo hacen. Además, un cambio parcial —configuras tres variables, vuelves a desplegar y configuras una cuarta— deja una de ellas sin aplicar.
dockup env list my-project/my-api --json # what is configured
dockup restart my-project/my-api # make the process re-read it
La comprobación definitiva consiste en leer la variable desde dentro del contenedor en ejecución, no desde el dashboard.
dockup exec "printenv | sort" my-project/my-api
Si aparece en esa salida y tu aplicación sigue indicando que es undefined, el problema está en tu código. Si no aparece, el problema está en la configuración. Ese único comando divide el espacio de búsqueda por la mitad.
5. Ámbito incorrecto
Normalmente, las variables tienen un ámbito: un servicio, un entorno o un proyecto. Una variable configurada en producción no es visible en un entorno de preview. Tampoco lo es una configurada en otro servicio del mismo proyecto.
Esta suele ser la causa cuando algo funciona en un sitio y no en otro con un código idéntico.
El orden de diagnóstico
# 1. Is it actually in the container's environment?
dockup exec "printenv | sort" my-project/my-api
# 2. Is it configured on the service you think it is?
dockup env list my-project/my-api --json
# 3. Is the running process older than the change?
dockup status my-project/my-api --json
Empieza siempre por el paso 1. Convierte un problema ambiguo en uno de dos problemas inequívocos.
En particular, los secretos
Hay dos hábitos que conviene adoptar independientemente de la plataforma.
Marca los secretos como secretos. En Dockup, una variable marcada como secreta aparece enmascarada en los listados y las respuestas de la API: dockup env list muestra ******** en lugar del valor. Esto es más importante de lo que parece, porque la forma más habitual en que se filtra una credencial no es un ataque, sino una captura de pantalla, un ticket de soporte o una línea de log.
Mantén los secretos fuera de los argumentos de compilación y de los bundles del frontend. Cualquiera que obtenga el artefacto puede leerlos. La regla general es la siguiente: si acaba en un archivo que distribuyes, ya no es un secreto.
Preguntas frecuentes
¿Por qué mi variable de entorno aparece como undefined durante la compilación? Porque la compilación y el tiempo de ejecución son entornos independientes. Las variables de ejecución no existen mientras se está compilando la imagen. Usa un argumento de compilación si realmente necesitas un valor durante la compilación, pero nunca un secreto.
¿Por qué mi frontend no detecta la variable?
Los bundlers sustituyen el valor durante la compilación y solo exponen nombres con prefijo: VITE_, NEXT_PUBLIC_. Para cambiar la variable debes volver a compilar, y todo lo que expongas de esta forma se puede leer públicamente.
¿Tengo que reiniciar después de cambiar una variable?
Sí. Un proceso en ejecución ya ha leído su entorno. La mayoría de las plataformas vuelve a desplegar automáticamente cuando se produce un cambio; compruébalo con printenv dentro del contenedor en lugar de confiar en el dashboard.
¿Cómo paso un valor multilínea, como una clave privada? Codifícalo en Base64, configura la cadena codificada y descodifícala en la aplicación. Los campos de variables de entorno de una sola línea eliminan los saltos de línea y producen errores de análisis que no los mencionan.
