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_VAREn 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 restartY 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-recreateO si prefieres una secuencia más explícita:
docker-compose down
docker-compose up -dLa 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:
Defino todo en
.envcon comillas simples:MYSQL_ROOT_PASSWORD='R00t!$pecial#Pass' MYSQL_USER='admin' MYSQL_PASSWORD='Pass$word@123'Referencia en
docker-compose.yml:environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_PASSWORD: ${MYSQL_PASSWORD}Después de modificar
.env, siempre uso:docker-compose up -d --force-recreateVerifico que los cambios se aplicaron:
docker-compose exec servicio env | grep MI_VAR
Lecciones aprendidas#
- Los caracteres especiales
$,!,@,#en valores requieren comillas simples restartsolo reinicia, no recarga configuración--force-recreatees 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.
Equipamiento recomendado#
- Raspberry Pi 3 B+ — Servidor ligero de bajo consumo para empezar tu homelab
- Raspberry Pi 4 (4GB) — La base perfecta para homelab, Docker y monitorización
Enlaces de afiliado. Sin coste extra para ti.