Arranque y actualizaciones
Qué hace la plataforma en cada arranque, pasos críticos y cosméticos, cómo ver los errores de despliegue y cómo actualizar Moodle, los plugins y los parches.
La Academia se configura sola: cada vez que arranca el contenedor moodle (primer despliegue, Redeploy, reinicio o restauración) vuelve a aplicar toda la configuración desde el código. Esta página explica ese proceso y cómo actualizar las versiones fijadas.
Construcción de la imagen
La imagen delta-lms/moodle:4.5 se construye con infrastructure/moodle/Dockerfile:
- Parte de
moodlehq/moodle-php-apache:8.3e instalagit,curl,python3y las librerías de Python del importador de documentos (pypdf,python-docx,openpyxl). - Ajusta PHP y Apache para producción: errores al registro y no a la pantalla,
memory_limit=512M, subidas de hasta 512 MB,max_execution_time=300, zona horariaAmerica/Guayaquily carpetas de desarrollo (behat,vendor,node_modules,.git) inaccesibles desde la web. - Hace que el contenedor prefiera IPv4 (
/etc/gai.conf), porque el servidor no tiene salida IPv6 y el correo de Office 365 fallaba con "Network is unreachable". - Descarga Moodle y los plugins de terceros en versiones fijas (ver la tabla de versiones más abajo).
- Copia los scripts de arranque, los logos, las fuentes, el inventario de contenidos, los plugins propios, las traducciones y los scripts de respaldo (en
/opt/delta-lms). - Aplica los parches al código de Moodle y de los plugins y ejecuta
verify-patches.php: si un parche importante no quedó aplicado, la construcción falla.
Solo entran en la imagen los archivos permitidos en .dockerignore, que funciona como lista blanca. Un script nuevo que no se agregue ahí no llega al contenedor. Además, todos los scripts se copian en una sola capa: con una instrucción COPY por script se superó el límite de 127 capas de Docker ("max depth exceeded").
Qué pasa en cada arranque
Contenedor moodle (entrypoint.sh)
| Paso | Qué hace | Si falla |
|---|---|---|
[1-2/5] Base de datos y config.php | write-config.sh exige la contraseña de la base, espera a MariaDB hasta 5 minutos y genera config.php (valores escapados, sslproxy si la dirección es https, reverseproxy desactivado, preventexecpath activado, archivo de solo lectura) | El contenedor no arranca y el error se ve en Coolify |
[3/5] Instalación | Cuenta las tablas mdl_*. Si no hay ninguna, instala Moodle en español con el nombre del sitio y la cuenta de administrador | Sin MOODLE_ADMIN_PASSWORD la primera instalación se detiene con error |
[4/5] Actualización | Ejecuta upgrade.php --non-interactive siempre y luego purga las cachés | El despliegue se detiene: el sitio no arranca con la base a medio actualizar |
[5/5] Configuración | Ejecuta moodle-config.sh (ver abajo) | Los pasos marcados step no detienen el arranque |
| Permisos | Dueño www-data en moodledata, config.php en modo 440 | — |
| Apache | apache2-foreground | — |
Las cachés se purgan antes de los scripts de configuración porque moodledata (donde viven las cachés) se conserva entre despliegues y lo comparten moodle y moodle-cron: sin esa purga, las clases nuevas de los plugins no se encuentran.
Contenedor moodle-cron (cron-entrypoint.sh)
- Genera el mismo
config.phpconwrite-config.sh(los dos contenedores usan siempre el mismo). - Espera a que exista la tabla
mdl_config(es decir, a quemoodletermine de instalar), reintentando cada 10 segundos. - Ejecuta
admin/cli/cron.phpcada 60 segundos, para siempre. - Cada ejecución correcta escribe la hora en
/tmp/cron-last-ok, que usa el control de salud.
El cron nunca tumba su contenedor: si una ejecución falla, escribe !!! [cron] ERROR en el registro, sigue reintentando y el control de salud lo marca unhealthy. Si Moodle responde upgrade pending durante 10 minutos seguidos, el registro avisa que la imagen del cron no coincide con la del sitio y que hay que redesplegar.
moodle-config.sh: ajustes y pasos
moodle-config.sh es idempotente: sobrescribe cada valor en cada arranque. Tiene dos tipos de instrucciones.
Ajustes directos
Se aplican con admin/cli/cfg.php: idioma (es), zona horaria (America/Guayaquil), país (EC), tema Boost Union con los colores y estilos de Deltamontero, cabecera HTML adicional (fuentes, chat de IA, ajustes de interfaz), seguridad, archivos, correo, rendimiento, cursos, calificaciones, editor, H5P, certificados, nombre del sitio, servicios web y la recompilación del tema.
Ajustes de seguridad relevantes para TI:
| Ajuste | Valor |
|---|---|
cronclionly | 1 (el cron solo corre desde la consola) |
| Política de contraseñas | Activada, mínimo 10 caracteres (passwordpolicy=1, minpasswordlength=10) |
sessiontimeout | 7200 s (2 horas) |
cookiesecure, cookiehttponly | 1 |
| Bloqueo de cuenta | 10 contraseñas fallidas en 30 minutos bloquean la cuenta 30 minutos |
| Invitados | Sin botón de invitado ni Área personal de invitado |
| IP real | getremoteaddrconf=1 y reverseproxyignore con las redes de Docker y de Cloudflare |
| MFA | Solo para super administradores: app de autenticación (TOTP), 7 días de gracia |
| Tamaño máximo de subida | 500 MB |
| Copias automáticas por curso de Moodle | Apagadas (backup_auto_active=0): el respaldo lo hace el servidor |
| Servicios web | Activados, protocolos rest y mcp |
moodle-config.sh se ejecuta con set -e. Si falla uno de estos ajustes directos (que no están dentro de un step), el script termina con error y, como entrypoint.sh también se detiene ante errores, el contenedor moodle no termina de arrancar. El motivo queda en el registro del contenedor.
Pasos críticos y cosméticos
Los scripts de la Academia se ejecutan con la función step:
step <critico|cosmetico> "<descripción>" <comando…>Un paso que falla nunca detiene el arranque, pero tampoco falla en silencio: muestra las últimas 25 líneas de su salida en el registro y anota la descripción en la lista de errores del despliegue.
- critico: permisos, seguridad, certificados o reglas. En el registro aparece
!!! ERROR en un paso de seguridad del despliegue: <descripción>. - cosmetico: aspecto y textos. En el registro aparece
! Aviso: falló un paso no crítico: <descripción>.
Pasos actuales, en orden de ejecución:
| Tipo | Script | Qué asegura |
|---|---|---|
| cosmético | set-logos.php | Logos corporativos y fondo |
| crítico | setup-mcp-service.php | Servicio web MCP (cuenta técnica, rol y token; el token no se imprime completo) |
| cosmético | rename-brand.php | Corrección de marca a "Deltamontero" |
| cosmético | create-certificate-template.php | Plantilla del certificado |
| cosmético | (comando PHP en línea) | Reparar certificados con un modo de entrega inválido |
| crítico | enable-video-completion.php | Completado automático de todos los videos al verlos hasta el final |
| crítico | configure-quiz-completion-gate.php | Cuestionarios marcados al rendirlos y bloqueados hasta ver su video |
| crítico | apply-partial-content-by-cargo.php | Contenido parcial por cargo |
| crítico | gate-certificates.php | Bloqueo de certificados hasta completar el módulo |
| crítico | configure-exam-security.php | Seguridad de exámenes (2 intentos, ventana segura, orden aleatorio, navegación secuencial) |
| crítico | normalize-academy.php | Estándar de la Academia en todos los módulos |
| crítico | build-intro-manual.php | Curso de Introducción = manual de la Academia |
| crítico | configure-forgot-password-url.php | "¿Olvidó su contraseña?" lleva a la recuperación con usuario y cédula |
| cosmético | customize-strings.php | Textos en español |
| crítico | align-gerencia-to-manual.php | Permisos de Gerencia según el manual |
| crítico | create-second-superadmin.php | Segunda cuenta de super administrador (una sola vez, si existe MOODLE_BACKUP_ADMIN_PASSWORD); recuerda en el registro si sigue activo el aviso de contraseña por defecto de admin |
| crítico | enforce-real-quiz-attempts.php | Intentos reales en cuestionarios (nadie previsualiza salvo el super administrador) |
| crítico | enforce-course-creation-manual.php | Solo el Jefe de Talento Humano crea cursos |
| crítico | align-access-profiles-to-manual.php | Perfiles de acceso y cohortes según el manual |
| cosmético | align-academy-to-manual.php | Cursos, temas, objetivos y registro de revisión según el manual |
| cosmético | configure-dataformats.php | Formatos de descarga (Excel, Word, PDF con formato Deltamontero, CSV) |
| crítico | apply-content-responsibilities.php | Responsables de actualizar contenido |
| cosmético | integrate-complementary-into-m6.php | Integración única de "Formación Complementaria — Líderes" al Módulo 6 |
| crítico | align-enrolments-to-manual.php | Matrículas del personal = ruta obligatoria del manual (una vez) |
| crítico | remove-courses-outside-manual.php | Eliminar una vez los cursos fuera del índice del manual |
| crítico | gate-certificates.php | Recalcular el bloqueo de certificados |
| crítico | configure-ai-groq.php | Solo si GROQ_API_KEY está definida: proveedor Groq del chat de IA con esa clave (cambiar la clave en Coolify y hacer Redeploy basta) |
| cosmético | configure-ai-quotas-and-persona.php | Cuotas de IA por rol e instrucciones del asistente |
| cosmético | configure-ai-terms.php | Condiciones de uso del Asistente de IA |
| crítico | apply-pending-emails.php | Aplicar correos pendientes de confirmar |
| crítico | rename-usernames.php | Nombres de usuario definitivos revisados por Talento Humano (renombra la cuenta del personal cuyo usuario actual es uno de los anteriores, si el nuevo está libre) |
| cosmético | clean-guillemets.php | Textos sin comillas angulares (una vez) |
| crítico | set-tests-one-attempt.php | Pruebas técnicas con 1 intento (una vez) |
| crítico | configure-mail.php | Solo salen los correos de la Academia (las notificaciones de Moodle quedan en la campana) |
| cosmético | configure-course-editor.php | Editor de los módulos |
| cosmético | configure-tours.php | Recorridos guiados |
| cosmético | (comando PHP en línea) | Historial de contexto del chat de IA a 50 mensajes |
| cosmético | (comando PHP en línea) | Ocultar la categoría vacía por defecto |
Al final, moodle-config.sh guarda el resultado en la configuración de Moodle y purga las cachés:
Clave (componente local_deltamodules) | Contenido |
|---|---|
deploy_errors | Lista de pasos fallidos con el formato [tipo] descripción, separados por una barra vertical. Vacío = todo bien |
deploy_time | Hora del último despliegue |
Cómo ver los errores de despliegue
En Moodle
Entre como super administrador. En el Área personal y en Administración del sitio aparece el recuadro Avisos para el super administrador con el texto "En el último despliegue (fecha) fallaron estos pasos: ...". Si no hay errores, el aviso no aparece. Ver Monitoreo y avisos.
En el registro del contenedor
En Coolify, los registros del servicio moodle. En local:
docker compose logs -f moodleBusque !!! ERROR en un paso de seguridad del despliegue, ! Aviso: falló un paso no crítico y la línea final !!! Pasos con errores en este despliegue:. Justo encima de cada una están las últimas 25 líneas de la salida del paso.
Repetir el paso a mano
La mayoría de los scripts indica en su cabecera cómo ejecutarlo por separado, por ejemplo php /configure-mail.php, dentro del contenedor moodle (en Coolify, su Terminal; en local, docker exec -it delta-lms_app bash).
php /configure-mail.phpEn el arranque estos scripts corren como root y, al final, entrypoint.sh devuelve la propiedad de moodledata a www-data. Si ejecuta uno a mano y crea archivos en moodledata, esos archivos quedan de root hasta el siguiente arranque: si después aparecen errores de permisos en cachés, reinicie el contenedor moodle.
Corrija la causa (normalmente en el código) y haga un Redeploy para que el aviso desaparezca: la lista de errores se reescribe en cada despliegue.
Versiones fijadas
Moodle y los plugins de terceros están fijados a un commit exacto con git-at (un script que clona solo ese commit). Así la imagen tiene siempre las mismas versiones: un cambio del autor de un plugin no rompe la imagen ni desactiva en silencio un parche.
| Componente | Repositorio | Versión fijada |
|---|---|---|
| Moodle 4.5 LTS (núcleo) | moodle/moodle | commit 89ae02d0007418c50f0911148137f4cb3bd67f4a |
theme_boost_union | moodle-an-hochschulen/moodle-theme_boost_union | commit 3d2b713240b3776bca785e487d10ad6f8e59f967 |
mod_hvp (H5P) | h5p/h5p-moodle-plugin | commit 6527ec556a198f217469f7cefa7d7bdcfcfb6f27, con submódulos |
mod_interactivevideo | sokunthearithmakara/mod_interactivevideo | commit e5c601683026cd90430e5e0c085211661a1e726d |
mod_customcert | mdjnelson/moodle-mod_customcert | commit 84cb6dfa2d10715387ddc6dad308ed2e0dcd817e |
tool_certificate | moodleworkplace/moodle-tool_certificate | commit 71bf23b49900a579d6f06e74f0eb2768078d7a42 (sin element/program, que exige Workplace) |
mod_coursecertificate | moodleworkplace/moodle-mod_coursecertificate | commit 2a2a10d539888b824a7875923a09931f50d982cd |
local_ai_manager | bycs-lp/moodle-local_ai_manager | etiqueta v1.1 (la v2.0 o superior exige Moodle 5.0) |
tiny_ai | bycs-lp/moodle-tiny_ai | etiqueta v1.0 |
block_ai_chat | bycs-lp/moodle-block_ai_chat | etiqueta v1.0 (última compatible con 4.5) |
block_sharing_cart | donhinkelman/moodle-block_sharing_cart | commit 2e5cef495e4bf8537df35f01c0d3ce23d4b89344 |
webservice_mcp | onbirdev/moodle-webservice_mcp | commit 198246e5d7121b7658e72e44549006753136ac70 |
Imágenes de los demás servicios: mariadb:11.4 y traefik:v3 (etiquetas, no commits).
Parches verificados
Durante la construcción se aplican parches al código de Moodle y de los plugins. verify-patches.php comprueba que estos ocho quedaron aplicados (si falta uno, la construcción falla):
| Parche | Archivo que modifica |
|---|---|
| Perfil del usuario en el chat de IA | local/ai_manager/classes/external/submit_query.php |
| Asistente de gestión del chat de IA | local/ai_manager/classes/external/submit_query.php |
| Política del sitio en una sola página | admin/tool/policy/classes/output/page_agreedocs.php |
| "¿Olvidó su contraseña?" sin correo | login/forgot_password_form.php |
| Saludo con nombre y apellido | lib/classes/user.php |
| Chat de IA en todas las páginas | local/ai_manager/classes/local/userinfo.php |
| Campo Cédula en el perfil | user/editlib.php |
| Certificado solo con el módulo completo | mod/customcert/view.php |
Otros tres parches son cosméticos y nunca detienen la construcción: botón de copiar y datos para borrar chats (patch-ai-chat-copy.php, patch-ai-chat-ui.php) y completado de video sin animación de felicitación (patch-video-completion.php).
Actualizar Moodle y los plugins
Moodle no admite volver a una versión anterior. Una vez que una imagen nueva actualiza la base de datos, un respaldo anterior solo se puede restaurar con una imagen de la misma versión o más nueva. Antes de actualizar en producción, saque un respaldo.
Cambiar la versión en el Dockerfile
Reemplace el commit (o la etiqueta) del componente en infrastructure/moodle/Dockerfile. El propio Dockerfile lo indica: "Para actualizar un plugin: cambiar el commit aquí y probar".
Construir y probar en local
docker compose build moodle
docker compose up -d
docker compose logs -f moodleSi la construcción falla en verify-patches.php, un parche ya no encuentra dónde aplicarse en la versión nueva: hay que adaptarlo (ver Desarrollo). Para probar la actualización con datos reales, restaure antes un respaldo de producción en local con restore.sh --local (sin correo o con desvío).
Compruebe que upgrade.php termina sin errores, que no hay errores de despliegue y que los videos interactivos, los repasos, los certificados y el chat de IA funcionan.
Respaldar producción
/opt/delta-lms/infrastructure/scripts/backup.sh /var/backups/delta-lmsPublicar
Suba el cambio al repositorio y haga un Redeploy en Coolify. El arranque ejecuta upgrade.php solo. Revise que moodle y moodle-cron queden healthy y que no haya avisos de despliegue.
Política de actualizaciones
El plan del proyecto (docs/roadmap_v4.md §3.3) propone:
- Automático: solo los parches de seguridad del sistema operativo del servidor (
unattended-upgradeslimitado al canal de seguridad). - Manual, con aprobación de TI y en una ventana trimestral: kernel, versión mayor del sistema operativo, imágenes Docker (Moodle, MariaDB) y plugins, siempre probando antes en local.
Si esta política ya está aplicada en el servidor: Por confirmar con TI.
El plan también tenía pendiente comprobar en Moodle 4.5 una actividad H5P (mod_hvp) y un video interactivo después de cada construcción (tarea F1.0b del roadmap). Los plugins ya están fijados a commits; el resultado de esa prueba de humo no está registrado: Por confirmar.
Variables de entorno
Todas las variables de docker-compose.yml y .env.example, para qué sirven, si son obligatorias y su valor por defecto, más las variables de los scripts de respaldo.
Respaldos
Qué se respalda, cómo se activa el respaldo diario en el servidor, cómo se vigila desde Moodle y cómo configurar la copia cifrada fuera del servidor.