Despliegue: usar los nombres nativos de MySQL en lugar de interpolar

Coolify escribe `null` al inlinear una variable marcada como `mostrar una
sola vez`, asi que `MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}` se resolvia a
vacio, MySQL se negaba a inicializar y el contenedor entraba en bucle de
reinicio; `web` abortaba con `dependency failed to start`.

Ahora el compose declara las variables en lista y por nombre pelado, sin
interpolacion, y el portal acepta MYSQL_DATABASE / MYSQL_USER / MYSQL_PASSWORD
como alternativa a los DB_*. Un solo juego de variables alimenta a los dos
contenedores.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Uriel Jareth
2026-07-29 23:34:28 -06:00
co-authored by Claude Opus 5
parent 0b9c9c1dc2
commit 1ae2e9c010
2 changed files with 35 additions and 20 deletions
+25 -17
View File
@@ -7,29 +7,35 @@
# · SERVICE_FQDN_WEB_4180 le dice a Coolify qué servicio y puerto exponer. # · SERVICE_FQDN_WEB_4180 le dice a Coolify qué servicio y puerto exponer.
# · Los datos de MySQL viven en un volumen con nombre, así que sobreviven # · Los datos de MySQL viven en un volumen con nombre, así que sobreviven
# a un redespliegue. # a un redespliegue.
# · Ninguna contraseña está aquí: todas llegan como variables de entorno. # · Ninguna contraseña está aquí.
# #
# El compose de desarrollo es docker-compose.yml (solo MySQL). Este es el # Las variables van en LISTA y por NOMBRE PELADO, sin ${...}: Coolify inyecta
# de producción y levanta también el portal. # su valor tal cual. Con `MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}` el valor
# llegaba VACÍO, porque Coolify escribe `null` al inlinear una variable marcada
# como "mostrar una sola vez" y la interpolación se resolvía a nada; MySQL
# entonces se niega a inicializar y el contenedor entra en bucle.
#
# El compose de desarrollo es docker-compose.yml (solo MySQL). Este es el de
# producción y levanta también el portal.
# ===================================================================== # =====================================================================
services: services:
mysql: mysql:
image: mysql:8.0 image: mysql:8.0
restart: unless-stopped restart: unless-stopped
command: > command:
--character-set-server=utf8mb4 - '--character-set-server=utf8mb4'
--collation-server=utf8mb4_unicode_ci - '--collation-server=utf8mb4_unicode_ci'
environment: environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} - MYSQL_ROOT_PASSWORD
MYSQL_DATABASE: ${DB_NAME:-insta_portal} - MYSQL_DATABASE
MYSQL_USER: ${DB_USER:-insta} - MYSQL_USER
MYSQL_PASSWORD: ${DB_PASSWORD} - MYSQL_PASSWORD
volumes: volumes:
- 'insta_mysql_data:/var/lib/mysql' - 'insta_mysql_data:/var/lib/mysql'
healthcheck: healthcheck:
test: test:
- CMD-SHELL - CMD-SHELL
- 'mysqladmin ping -h 127.0.0.1 -uroot -p$${MYSQL_ROOT_PASSWORD} --silent' - 'mysqladmin ping -h 127.0.0.1 -uroot -p"$$MYSQL_ROOT_PASSWORD" --silent'
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 30 retries: 30
@@ -47,18 +53,20 @@ services:
# A MySQL por nombre de servicio, nunca localhost. # A MySQL por nombre de servicio, nunca localhost.
- DB_HOST=mysql - DB_HOST=mysql
- DB_PORT=3306 - DB_PORT=3306
- 'DB_NAME=${DB_NAME:-insta_portal}' # El portal lee estos mismos nombres (ver server/config.mjs), así que no
- 'DB_USER=${DB_USER:-insta}' # hace falta un segundo juego de variables ni interpolarlas.
- 'DB_PASSWORD=${DB_PASSWORD}' - MYSQL_DATABASE
- MYSQL_USER
- MYSQL_PASSWORD
# Detrás de Traefik: cookie Secure y la IP real para la bitácora. # Detrás de Traefik: cookie Secure y la IP real para la bitácora.
- COOKIE_SEGURA=true - COOKIE_SEGURA=true
- CONFIAR_PROXY=true - CONFIAR_PROXY=true
# La demostración muestra el enlace de acceso en pantalla a propósito, # La demostración muestra el enlace de acceso en pantalla a propósito,
# para que cualquiera pueda entrar a probarla con un clic. # para que cualquiera pueda entrar a probarla con un clic.
- 'MOSTRAR_ENLACE=${MOSTRAR_ENLACE:-true}' - MOSTRAR_ENLACE
# true en un redespliegue devuelve la demo a su estado inicial. # true en un redespliegue devuelve la demo a su estado inicial.
- 'SEMBRAR_SIEMPRE=${SEMBRAR_SIEMPRE:-false}' - SEMBRAR_SIEMPRE
- 'ENLACES_POR_VENTANA=${ENLACES_POR_VENTANA:-60}' - ENLACES_POR_VENTANA
depends_on: depends_on:
mysql: mysql:
condition: service_healthy condition: service_healthy
+10 -3
View File
@@ -4,12 +4,19 @@ const bandera = (valor, porOmision) => (valor === undefined ? porOmision : valor
export const config = { export const config = {
port: Number(process.env.PORT ?? 4180), port: Number(process.env.PORT ?? 4180),
/**
* Se aceptan los nombres nativos de la imagen de MySQL (MYSQL_DATABASE,
* MYSQL_USER, MYSQL_PASSWORD) además de los DB_*. Así, al desplegar, un
* solo juego de variables alimenta a los dos contenedores y no hay que
* mantener dos nombres para el mismo dato ni interpolar nada en el compose.
*/
db: { db: {
host: process.env.DB_HOST ?? '127.0.0.1', host: process.env.DB_HOST ?? '127.0.0.1',
port: Number(process.env.DB_PORT ?? 3307), port: Number(process.env.DB_PORT ?? 3307),
user: process.env.DB_USER ?? 'root', user: process.env.DB_USER ?? process.env.MYSQL_USER ?? 'root',
password: process.env.DB_PASSWORD ?? 'insta_root_demo', password: process.env.DB_PASSWORD ?? process.env.MYSQL_PASSWORD ?? 'insta_root_demo',
database: process.env.DB_NAME ?? 'insta_portal', database: process.env.DB_NAME ?? process.env.MYSQL_DATABASE ?? 'insta_portal',
}, },
// Vigencia del enlace de acceso y de la sesión, en minutos. // Vigencia del enlace de acceso y de la sesión, en minutos.