Academia Deltamontero · Documentación
Operación y mantenimiento

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:

  1. Parte de moodlehq/moodle-php-apache:8.3 e instala git, curl, python3 y las librerías de Python del importador de documentos (pypdf, python-docx, openpyxl).
  2. 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 horaria America/Guayaquil y carpetas de desarrollo (behat, vendor, node_modules, .git) inaccesibles desde la web.
  3. 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".
  4. Descarga Moodle y los plugins de terceros en versiones fijas (ver la tabla de versiones más abajo).
  5. 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).
  6. 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)

PasoQué haceSi falla
[1-2/5] Base de datos y config.phpwrite-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ónCuenta las tablas mdl_*. Si no hay ninguna, instala Moodle en español con el nombre del sitio y la cuenta de administradorSin MOODLE_ADMIN_PASSWORD la primera instalación se detiene con error
[4/5] ActualizaciónEjecuta upgrade.php --non-interactive siempre y luego purga las cachésEl despliegue se detiene: el sitio no arranca con la base a medio actualizar
[5/5] ConfiguraciónEjecuta moodle-config.sh (ver abajo)Los pasos marcados step no detienen el arranque
PermisosDueño www-data en moodledata, config.php en modo 440—
Apacheapache2-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)

  1. Genera el mismo config.php con write-config.sh (los dos contenedores usan siempre el mismo).
  2. Espera a que exista la tabla mdl_config (es decir, a que moodle termine de instalar), reintentando cada 10 segundos.
  3. Ejecuta admin/cli/cron.php cada 60 segundos, para siempre.
  4. 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:

AjusteValor
cronclionly1 (el cron solo corre desde la consola)
Política de contraseñasActivada, mínimo 10 caracteres (passwordpolicy=1, minpasswordlength=10)
sessiontimeout7200 s (2 horas)
cookiesecure, cookiehttponly1
Bloqueo de cuenta10 contraseñas fallidas en 30 minutos bloquean la cuenta 30 minutos
InvitadosSin botón de invitado ni Área personal de invitado
IP realgetremoteaddrconf=1 y reverseproxyignore con las redes de Docker y de Cloudflare
MFASolo para super administradores: app de autenticación (TOTP), 7 días de gracia
Tamaño máximo de subida500 MB
Copias automáticas por curso de MoodleApagadas (backup_auto_active=0): el respaldo lo hace el servidor
Servicios webActivados, 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:

TipoScriptQué asegura
cosméticoset-logos.phpLogos corporativos y fondo
críticosetup-mcp-service.phpServicio web MCP (cuenta técnica, rol y token; el token no se imprime completo)
cosméticorename-brand.phpCorrección de marca a "Deltamontero"
cosméticocreate-certificate-template.phpPlantilla del certificado
cosmético(comando PHP en línea)Reparar certificados con un modo de entrega inválido
críticoenable-video-completion.phpCompletado automático de todos los videos al verlos hasta el final
críticoconfigure-quiz-completion-gate.phpCuestionarios marcados al rendirlos y bloqueados hasta ver su video
críticoapply-partial-content-by-cargo.phpContenido parcial por cargo
críticogate-certificates.phpBloqueo de certificados hasta completar el módulo
críticoconfigure-exam-security.phpSeguridad de exámenes (2 intentos, ventana segura, orden aleatorio, navegación secuencial)
críticonormalize-academy.phpEstándar de la Academia en todos los módulos
críticobuild-intro-manual.phpCurso de Introducción = manual de la Academia
críticoconfigure-forgot-password-url.php"¿Olvidó su contraseña?" lleva a la recuperación con usuario y cédula
cosméticocustomize-strings.phpTextos en español
críticoalign-gerencia-to-manual.phpPermisos de Gerencia según el manual
críticocreate-second-superadmin.phpSegunda 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íticoenforce-real-quiz-attempts.phpIntentos reales en cuestionarios (nadie previsualiza salvo el super administrador)
críticoenforce-course-creation-manual.phpSolo el Jefe de Talento Humano crea cursos
críticoalign-access-profiles-to-manual.phpPerfiles de acceso y cohortes según el manual
cosméticoalign-academy-to-manual.phpCursos, temas, objetivos y registro de revisión según el manual
cosméticoconfigure-dataformats.phpFormatos de descarga (Excel, Word, PDF con formato Deltamontero, CSV)
críticoapply-content-responsibilities.phpResponsables de actualizar contenido
cosméticointegrate-complementary-into-m6.phpIntegración única de "Formación Complementaria — Líderes" al Módulo 6
críticoalign-enrolments-to-manual.phpMatrículas del personal = ruta obligatoria del manual (una vez)
críticoremove-courses-outside-manual.phpEliminar una vez los cursos fuera del índice del manual
críticogate-certificates.phpRecalcular el bloqueo de certificados
críticoconfigure-ai-groq.phpSolo 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éticoconfigure-ai-quotas-and-persona.phpCuotas de IA por rol e instrucciones del asistente
cosméticoconfigure-ai-terms.phpCondiciones de uso del Asistente de IA
críticoapply-pending-emails.phpAplicar correos pendientes de confirmar
críticorename-usernames.phpNombres 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éticoclean-guillemets.phpTextos sin comillas angulares (una vez)
críticoset-tests-one-attempt.phpPruebas técnicas con 1 intento (una vez)
críticoconfigure-mail.phpSolo salen los correos de la Academia (las notificaciones de Moodle quedan en la campana)
cosméticoconfigure-course-editor.phpEditor de los módulos
cosméticoconfigure-tours.phpRecorridos 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_errorsLista de pasos fallidos con el formato [tipo] descripción, separados por una barra vertical. Vacío = todo bien
deploy_timeHora 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 moodle

Busque !!! 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.php

En 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.

ComponenteRepositorioVersión fijada
Moodle 4.5 LTS (núcleo)moodle/moodlecommit 89ae02d0007418c50f0911148137f4cb3bd67f4a
theme_boost_unionmoodle-an-hochschulen/moodle-theme_boost_unioncommit 3d2b713240b3776bca785e487d10ad6f8e59f967
mod_hvp (H5P)h5p/h5p-moodle-plugincommit 6527ec556a198f217469f7cefa7d7bdcfcfb6f27, con submódulos
mod_interactivevideosokunthearithmakara/mod_interactivevideocommit e5c601683026cd90430e5e0c085211661a1e726d
mod_customcertmdjnelson/moodle-mod_customcertcommit 84cb6dfa2d10715387ddc6dad308ed2e0dcd817e
tool_certificatemoodleworkplace/moodle-tool_certificatecommit 71bf23b49900a579d6f06e74f0eb2768078d7a42 (sin element/program, que exige Workplace)
mod_coursecertificatemoodleworkplace/moodle-mod_coursecertificatecommit 2a2a10d539888b824a7875923a09931f50d982cd
local_ai_managerbycs-lp/moodle-local_ai_manageretiqueta v1.1 (la v2.0 o superior exige Moodle 5.0)
tiny_aibycs-lp/moodle-tiny_aietiqueta v1.0
block_ai_chatbycs-lp/moodle-block_ai_chatetiqueta v1.0 (última compatible con 4.5)
block_sharing_cartdonhinkelman/moodle-block_sharing_cartcommit 2e5cef495e4bf8537df35f01c0d3ce23d4b89344
webservice_mcponbirdev/moodle-webservice_mcpcommit 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):

ParcheArchivo que modifica
Perfil del usuario en el chat de IAlocal/ai_manager/classes/external/submit_query.php
Asistente de gestión del chat de IAlocal/ai_manager/classes/external/submit_query.php
Política del sitio en una sola páginaadmin/tool/policy/classes/output/page_agreedocs.php
"¿Olvidó su contraseña?" sin correologin/forgot_password_form.php
Saludo con nombre y apellidolib/classes/user.php
Chat de IA en todas las páginaslocal/ai_manager/classes/local/userinfo.php
Campo Cédula en el perfiluser/editlib.php
Certificado solo con el módulo completomod/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 moodle

Si 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-lms

Publicar

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-upgrades limitado 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.

En esta página