diff --git a/docker-compose.coolify.yml b/docker-compose.coolify.yml index 65e15d8..109f289 100644 --- a/docker-compose.coolify.yml +++ b/docker-compose.coolify.yml @@ -7,29 +7,35 @@ # · 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 # 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 -# de producción y levanta también el portal. +# Las variables van en LISTA y por NOMBRE PELADO, sin ${...}: Coolify inyecta +# 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: mysql: image: mysql:8.0 restart: unless-stopped - command: > - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci + command: + - '--character-set-server=utf8mb4' + - '--collation-server=utf8mb4_unicode_ci' environment: - MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} - MYSQL_DATABASE: ${DB_NAME:-insta_portal} - MYSQL_USER: ${DB_USER:-insta} - MYSQL_PASSWORD: ${DB_PASSWORD} + - MYSQL_ROOT_PASSWORD + - MYSQL_DATABASE + - MYSQL_USER + - MYSQL_PASSWORD volumes: - 'insta_mysql_data:/var/lib/mysql' healthcheck: test: - 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 timeout: 5s retries: 30 @@ -47,18 +53,20 @@ services: # A MySQL por nombre de servicio, nunca localhost. - DB_HOST=mysql - DB_PORT=3306 - - 'DB_NAME=${DB_NAME:-insta_portal}' - - 'DB_USER=${DB_USER:-insta}' - - 'DB_PASSWORD=${DB_PASSWORD}' + # El portal lee estos mismos nombres (ver server/config.mjs), así que no + # hace falta un segundo juego de variables ni interpolarlas. + - MYSQL_DATABASE + - MYSQL_USER + - MYSQL_PASSWORD # Detrás de Traefik: cookie Secure y la IP real para la bitácora. - COOKIE_SEGURA=true - CONFIAR_PROXY=true # La demostración muestra el enlace de acceso en pantalla a propósito, # 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. - - 'SEMBRAR_SIEMPRE=${SEMBRAR_SIEMPRE:-false}' - - 'ENLACES_POR_VENTANA=${ENLACES_POR_VENTANA:-60}' + - SEMBRAR_SIEMPRE + - ENLACES_POR_VENTANA depends_on: mysql: condition: service_healthy diff --git a/server/config.mjs b/server/config.mjs index 2184e99..54f3983 100644 --- a/server/config.mjs +++ b/server/config.mjs @@ -4,12 +4,19 @@ const bandera = (valor, porOmision) => (valor === undefined ? porOmision : valor export const config = { 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: { host: process.env.DB_HOST ?? '127.0.0.1', port: Number(process.env.DB_PORT ?? 3307), - user: process.env.DB_USER ?? 'root', - password: process.env.DB_PASSWORD ?? 'insta_root_demo', - database: process.env.DB_NAME ?? 'insta_portal', + user: process.env.DB_USER ?? process.env.MYSQL_USER ?? 'root', + password: process.env.DB_PASSWORD ?? process.env.MYSQL_PASSWORD ?? 'insta_root_demo', + database: process.env.DB_NAME ?? process.env.MYSQL_DATABASE ?? 'insta_portal', }, // Vigencia del enlace de acceso y de la sesión, en minutos.