Configuración automática
Qué pasa en cada arranque del contenedor moodle, desde la espera de la base de datos hasta el aviso de errores al super administrador.
La plataforma no se configura a mano desde la web: en cada arranque del contenedor moodle se reaplica toda la configuración desde el código. Así, un despliegue nuevo, un reinicio o una restauración terminan siempre en el mismo estado.
Flujo de arranque
entrypoint.sh
├─ [1-2/5] write-config.sh
│ ├─ exige MOODLE_DB_PASSWORD (si falta, el contenedor no arranca)
│ ├─ espera a MariaDB (cada 3 s, máximo 5 minutos)
│ └─ genera config.php (valores escapados, solo lectura)
├─ [3/5] ¿hay tablas mdl_* en la base?
│ ├─ no → exige MOODLE_ADMIN_PASSWORD → install_database.php (español)
│ └─ sí → omite el instalador
├─ [4/5] admin/cli/upgrade.php --non-interactive
│ ├─ si falla → el contenedor termina con error (el despliegue se detiene)
│ └─ purge_caches.php
├─ [5/5] moodle-config.sh
│ ├─ ajustes directos con admin/cli/cfg.php
│ ├─ pasos "step critico|cosmetico" con scripts PHP
│ └─ guarda los pasos fallidos en local_deltamodules/deploy_errors
├─ permisos: moodledata → www-data; config.php → 440
└─ exec apache2-foregroundBase de datos y config.php
write-config.sh lo usan los dos contenedores (moodle y moodle-cron) para que su config.php sea siempre idéntico. No hay contraseñas por defecto: sin MOODLE_DB_PASSWORD el contenedor termina con un error visible en Coolify. Espera a la base hasta 100 intentos (unos 5 minutos).
El config.php generado contiene:
| Ajuste | Valor | Motivo |
|---|---|---|
dbtype / dblibrary | mariadb / native | |
dbhost, dbname, dbuser, dbpass | Desde las variables de entorno, escapados con var_export | Una comilla en la contraseña no rompe el archivo |
prefix | mdl_ | |
dbcollation | utf8mb4_unicode_ci | Igual que el servidor |
wwwroot | MOODLE_WWWROOT | Debe coincidir con la dirección que ven los usuarios (hoy http://192.168.0.192) |
dataroot | /var/www/moodledata | |
reverseproxy | false | Traefik no cambia el Host; con true Moodle falla con "reverseproxyabused" |
sslproxy | true solo si wwwroot empieza por https:// | Con la publicación por dominio (planificada), el TLS lo terminan Cloudflare y el proxy. Hoy, con http://, queda en false |
preventexecpath | true | Nadie puede cambiar desde la web rutas de programas del servidor |
El archivo queda con dueño root:www-data y permisos 440 (Apache lo lee pero no lo puede modificar).
Instalación solo si no hay tablas
El entrypoint.sh cuenta las tablas mdl_* con mysqli y SHOW TABLES. Si no hay ninguna, instala Moodle con install_database.php en español, con el nombre del sitio (MOODLE_SITE_NAME, por defecto "Academia Deltamontero"), el nombre corto (MOODLE_SITE_SHORTNAME, por defecto AcademiaDM) y la cuenta de administración inicial (MOODLE_ADMIN_USER, MOODLE_ADMIN_PASSWORD, MOODLE_ADMIN_EMAIL). Sin MOODLE_ADMIN_PASSWORD no instala.
Borrar moodledata no reinstala Moodle: solo se pierden los archivos. La reinstalación ocurre únicamente con la base vacía. Por eso restore.sh, si falla a medias, deja Moodle detenido a propósito: con la base vacía, el entrypoint reinstalaría.
Actualización
upgrade.php --non-interactive corre en cada arranque y aplica las actualizaciones de Moodle y de los plugins nuevos o modificados. Si falla, el contenedor termina con error y el sitio no arranca con la base a medio actualizar. Después se purgan las cachés, porque moodledata persiste entre despliegues y sin esa limpieza no se encuentran las clases nuevas de los plugins.
moodle-config.sh
Aplica la configuración del sitio. Todos los ajustes son idempotentes. Tiene dos tipos de instrucciones:
- Ajustes directos con
php admin/cli/cfg.php --name=... --set=.... - Pasos con la función
step <critico|cosmetico> "<descripción>" <comando>, que ejecuta un script PHP. Un paso que falla no detiene el arranque, pero tampoco falla en silencio: muestra las últimas 25 líneas de su salida en el registro, lo marca como error de seguridad (crítico) o como aviso (cosmético) y lo agrega a la lista de errores del despliegue.
Al terminar, guarda la lista en local_deltamodules/deploy_errors junto con la hora (deploy_time). El super administrador ve esos pasos fallidos como aviso en su Área personal y en Administración del sitio.
Permisos y Apache
Se ajusta el dueño de moodledata, se vuelve a fijar config.php en 440 y se arranca Apache en primer plano.
Qué configura moodle-config.sh
Ajustes directos
| Bloque | Ajustes principales |
|---|---|
| Idioma y región | lang=es, timezone=America/Guayaquil, country=EC, calendario gregoriano, dateformat="%d de %B de %Y" |
| Tema | theme=boost_union, color de marca #1361A4, variables SCSS previas (colores, radios, barra de navegación), SCSS propio (fuente Century Gothic, tokens de color, barra superior, cajones laterales, páginas de login, políticas y certificados, chat de IA) |
| HTML adicional | additionalhtmlhead con estilos y scripts globales: sin diálogos nativos del navegador, recorridos guiados, barra discreta con versión y hora, control de cambio de pantalla en exámenes, recarga de páginas restauradas desde la caché del historial, login, ojo de contraseña de "mantener presionado", validación de cédula, chat de IA en panel flotante, entre otros. Va en el encabezado y no en el pie porque Moodle omite el pie en las páginas de diseño embedded que usa el reproductor de video |
| Seguridad | Ver Seguridad: cron solo por consola, política de contraseñas, sesión, cookies, bloqueo de cuenta, sin invitados, IP real detrás de Cloudflare, MFA para super administradores |
| Archivos | Máximo de subida, por curso y cuota de usuario de 500 MB |
| Correo | Ver Correo: soporte, ingreso con correo, SMTP desde variables, desvío de pruebas |
| Rendimiento | Caché de JS y plantillas activas, themedesignermode=0, estadísticas desactivadas, caché de registros activa |
| Cursos | Finalización y disponibilidad condicional activas; matriculación manual, self y cohort; página de inicio = Área personal; portada institucional propia (customfrontpageinclude → local/deltamodules/frontpage.php); copias automáticas por curso apagadas; 10 secciones por defecto |
| Calificaciones | Porcentaje con 2 decimales, salvo que Talento Humano lo haya cambiado en Calificaciones de la Academia |
| Editor y H5P | Editores tiny,plain; seguimiento de H5P activo |
| Certificados | URL de verificación de tool_certificate activa |
| Videos | Reproductor de mod_interactivevideo en modo sin distracciones por defecto |
| IA | Entrada de navegación de local_ai_manager oculta (la administración está en Configuración IA) |
| Servicios web | enablewebservices=1, protocolos rest,mcp |
Pasos con scripts
| Paso | Script | Tipo |
|---|---|---|
| Logos corporativos y fondo | set-logos.php | cosmético |
| Servicio MCP (el token no se imprime completo) | setup-mcp-service.php | crítico |
| Corrección de marca (Delta Montero → Deltamontero) | rename-brand.php | cosmético |
| Plantilla de certificado | create-certificate-template.php | cosmético |
| Reparar opción de entrega de certificados | comando PHP en línea | cosmético |
| Completado automático de todos los videos (verlos hasta el final) | enable-video-completion.php | crítico |
| Cuestionarios: "Hecho" al rendirlos y candado hasta ver su video | configure-quiz-completion-gate.php | crítico |
| Contenido parcial por cargo (Tesorería en Módulos 2 y 5) | apply-partial-content-by-cargo.php | crítico |
| Bloqueo de certificados por completado | gate-certificates.php | crítico |
| Seguridad de exámenes | configure-exam-security.php | crítico |
| Estándar de la Academia en todos los módulos | normalize-academy.php | crítico |
| Curso de Introducción = manual de la Academia | build-intro-manual.php | crítico |
| "¿Olvidó su contraseña?" → recuperación con usuario y cédula | configure-forgot-password-url.php | crítico |
| Textos en español | customize-strings.php | cosmético |
| Permisos de Gerencia según el manual | align-gerencia-to-manual.php | crítico |
| Segundo super administrador de respaldo | create-second-superadmin.php | crítico |
| Intentos reales en cuestionarios (sin previsualización) | enforce-real-quiz-attempts.php | crítico |
| Crear cursos: solo el Jefe de Talento Humano | enforce-course-creation-manual.php | crítico |
| Perfiles de acceso y cohortes según el manual | align-access-profiles-to-manual.php | crítico |
| Cursos, temas y objetivos según el manual | align-academy-to-manual.php | cosmético |
| Formatos de descarga Excel, Word y PDF | configure-dataformats.php | cosmético |
| Responsables de actualizar contenido | apply-content-responsibilities.php | crítico |
| Integrar Formación Complementaria al Módulo 6 (una vez) | integrate-complementary-into-m6.php | cosmético |
| Matrículas del personal = ruta del manual (una vez) | align-enrolments-to-manual.php | crítico |
| Eliminar cursos fuera del manual (una vez) | remove-courses-outside-manual.php | crítico |
| Recalcular bloqueo de certificados | gate-certificates.php | crítico |
Chat de IA: proveedor Groq con la clave de GROQ_API_KEY (solo si la variable está definida) | configure-ai-groq.php | crítico |
| Cuotas de IA por perfil y persona del asistente | configure-ai-quotas-and-persona.php | cosmético |
| Condiciones de uso del Asistente de IA | configure-ai-terms.php | cosmético |
| Aplicar correos pendientes de confirmar | apply-pending-emails.php | crítico |
| Nombres de usuario definitivos (por nombre de usuario anterior) | rename-usernames.php | crítico |
| Textos sin comillas angulares (una vez) | clean-guillemets.php | cosmético |
| Pruebas técnicas con 1 intento (una vez) | set-tests-one-attempt.php | crítico |
| Correo: solo los correos de la Academia | configure-mail.php | crítico |
| Editor de los módulos | configure-course-editor.php | cosmético |
| Recorridos guiados | configure-tours.php | cosmético |
| Historial de contexto del chat de IA a 50 mensajes | comando PHP en línea | cosmético |
| Ocultar la categoría vacía por defecto | comando PHP en línea | cosmético |
Los pasos marcados "una vez" guardan una bandera en la configuración y no se repiten en los siguientes arranques (algunos aceptan --force). El resto se recalcula en cada arranque y respeta lo que Talento Humano haya ajustado después desde la interfaz cuando así lo indica su propio script.
El orden importa: por ejemplo, rename-brand.php corre antes de create-certificate-template.php, y apply-partial-content-by-cargo.php antes de gate-certificates.php. El orden vigente es el del archivo moodle-config.sh.
Scripts que no corren en el arranque
En la imagen hay otros scripts de infrastructure/moodle/ que no llama moodle-config.sh. Son de aprovisionamiento inicial, de importación o de uso puntual, y se ejecutan a mano con docker exec <contenedor moodle> php /<script>.php:
| Grupo | Scripts |
|---|---|
| Roles y permisos | rebuild-roles-per-manual.php, fix-role-assign-matrix-v2.php, grant-reports-access.php, grant-policy-report-access.php |
| Cursos y rutas | create-courses.php, create-onboarding-course.php, restructure-courses-per-manual.php, create-training-paths.php, configure-course-completion.php, configure-module-metadata.php, create-annual-review-event.php |
| Personas | import-personnel.php, create-user-area-field.php (el antiguo assign-users-to-cohorts.php se eliminó: los cargos se asignan en Personal Deltamontero o con la importación de Excel) |
| Selección de personal | create-selection-tests.php, import-selection-questions.php, configure-candidate-access.php, create-candidates-report.php |
| Informes | create-training-report.php, create-review-report.php |
| Políticas | configure-site-policy.php |
| IA | configure-ai-groq.php (también corre en el arranque cuando GROQ_API_KEY está definida), configure-ai-manager.php, configure-ai-chat-global.php, apply-default-ai-persona.php, import-rag-chunks.php |
| Contenido generado | import-checkpoints.php |
| Utilidades Python | parse-curriculum.py, parse-document.py, report-docx.py (las invoca el plugin) |
Orden recomendado de ejecución de estos scripts en una instalación desde cero: Por confirmar. El repositorio solo deja pistas sueltas en los encabezados (por ejemplo, configure-ai-chat-global.php después de configure-ai-quotas-and-persona.php, o configure-candidate-access.php después de create-selection-tests.php). En una recuperación con respaldo no hace falta ejecutarlos: lo que crearon ya está en la base de datos.
Configuración que sigue siendo manual
- Variables de entorno en Coolify (contraseñas, SMTP, claves de IA).
- Dominio y HTTPS en Coolify y Cloudflare, cuando se publique con dominio (planificado; hoy se usa la red interna).
- Respaldo diario en el host (
setup-backup.sh) y su copia externa. - Cambios de contenido y reglas que Talento Humano hace desde la interfaz (se guardan como datos y van en el respaldo).
Procedimientos detallados: Operación y mantenimiento.