Ir al contenido

Variables de entorno con caracteres especiales en Docker Compose: el problema del dollar y cómo recrear contenedores

Rogelio Guerra Riverón
Autor
Rogelio Guerra Riverón
Construyendo mi propia infraestructura web desde cero. Aquí documento cada paso: servidores, redes, contenedores y lo que vaya surgiendo.

El problema real
#

Llevo meses ejecutando servicios en mi servidor doméstico con Docker Compose. Hace poco intenté configurar una contraseña con caracteres especiales en mi archivo .env. La contraseña era algo como Pass$word123!@. Al iniciar los contenedores, la variable llegaba vacía o malformada. Después de investigar, descubrí que Docker Compose interpretaba el $ como referencia a otra variable.

Por qué sucede: interpolación de variables
#

Docker Compose interpreta el archivo .env de forma especial. Cuando encuentra un $ seguido de un nombre válido de variable, intenta sustituirlo por su valor. Si esa variable no existe, la deja vacía o genera un error silencioso.

Ejemplo del problema:

# .env
DB_PASSWORD=Pass$word123
API_KEY=sk_test_$random_key
SECRET=$UNDEFINED_VAR

En estos casos, Docker Compose buscará variables llamadas word123, random_key y UNDEFINED_VAR. Obviamente no las encontrará, y tus valores quedarán corruptos.

La solución: comillas simples
#

La solución más confiable es envolver los valores en comillas simples. Las comillas simples previenen la interpolación de variables en Docker Compose, exactamente como funcionan en bash.

# .env - FORMA CORRECTA
DB_PASSWORD='Pass$word123'
API_KEY='sk_test_$random_key'
SECRET='$UNDEFINED_VAR'
COMPLEX='!@#$%^&*()'

Con comillas simples, Docker Compose trata todo el contenido como texto literal. No intenta resolver referencias a variables.

Usando las variables en docker-compose.yml
#

Una vez definidas correctamente en .env, usarlas en tu docker-compose.yml es normal:

version: '3.8'
services:
  database:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USER}
  api:
    image: mi-api:latest
    environment:
      API_KEY: ${API_KEY}
      DB_SECRET: ${SECRET}

Docker Compose cargará los valores desde .env e inyectará las variables correctamente en los contenedores.

El segundo problema: restart no recarga variables
#

Aquí viene lo frustrante. Después de modificar tu archivo .env, ejecutas:

docker-compose restart

Y descubres que los contenedores siguen usando los valores antiguos. Esto sucede porque restart solo reinicia los contenedores existentes sin recrearlos. No vuelve a leer el archivo .env.

La solución: –force-recreate
#

Para que Docker Compose lea nuevamente el archivo .env y aplique las nuevas variables, debes recrear los contenedores. El comando correcto es:

docker-compose up -d --force-recreate

O si prefieres una secuencia más explícita:

docker-compose down
docker-compose up -d

La opción --force-recreate fuerza la recreación incluso si la imagen no ha cambiado. Sin ella, Docker Compose podría reutilizar contenedores existentes.

Mi flujo de trabajo actual
#

Después de experimentar con esto, así es como manejo las variables en mi servidor:

  1. Defino todo en .env con comillas simples:

    MYSQL_ROOT_PASSWORD='R00t!$pecial#Pass'
    MYSQL_USER='admin'
    MYSQL_PASSWORD='Pass$word@123'
  2. Referencia en docker-compose.yml:

    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
  3. Después de modificar .env, siempre uso:

    docker-compose up -d --force-recreate
  4. Verifico que los cambios se aplicaron:

    docker-compose exec servicio env | grep MI_VAR

Lecciones aprendidas
#

  • Los caracteres especiales $, !, @, # en valores requieren comillas simples
  • restart solo reinicia, no recarga configuración
  • --force-recreate es imprescindible tras modificar .env
  • Siempre verifica que las variables se hayan cargado correctamente dentro del contenedor

Estos detalles ahorraron muchas horas de debugging en mi setup doméstico. Espero que te ahorren también las tuyas.

📬 Recibe los nuevos artículos por email

Sin spam. Solo cuando publique algo nuevo. Puedes darte de baja cuando quieras.


Para ver los comentarios y reacciones, acepta las cookies funcionales en el banner.