Solución de problemas
Problemas conocidos de la Academia Deltamontero y cómo resolverlos, documentados en el código, sus comentarios y el manual de recuperación.
Problemas que ya ocurrieron o que el código prevé, con su causa y su solución. Antes de cambiar nada, revise los registros y los Avisos para el super administrador.
Dirección, proxy y dominio
Causa: MOODLE_WWWROOT no coincide exactamente con la dirección que ve el usuario.
Solución: en Coolify, MOODLE_WWWROOT con la dirección exacta que ven los usuarios, sin barra final (hoy http://192.168.0.192; con el dominio planificado, https://learning.deltamontero.net), y Redeploy. En local no se toca: docker-compose.override.yml la fija en http://localhost:8080. Si se restauró un respaldo de otra dirección, ejecute el comando de replace.php que muestra restore.sh al final.
Causa: Moodle construye las direcciones según X-Forwarded-Proto. Si el proxy no la envía como https, genera direcciones HTTP internas y falla la validación de tokens y recursos.
Solución: detrás de Cloudflare (publicación planificada), Cloudflare envía la cabecera; Traefik debe propagarla, no sobrescribirla. Con MOODLE_WWWROOT en https://, write-config.sh activa sslproxy. En el modo sin Coolify, el middleware moodle-headers de infrastructure/traefik/dynamic/moodle.yml la fija en https.
Causa: reverseproxy=true en config.php. Traefik no cambia el encabezado Host, y con ese ajuste Moodle falla.
Solución: write-config.sh deja siempre reverseproxy=false y regenera config.php en cada arranque. No lo cambie a mano.
Causa: etiquetas de Traefik manuales en el servicio moodle. Traefik ve dos servicios para el mismo router (el manual y el que genera Coolify) y no sabe a cuál enlazar ("cannot be linked automatically with multiple Services").
Solución: dejar comentadas las etiquetas en docker-compose.yml y configurar el dominio en Coolify (Domains). Solo se reactivan para el modo standalone sin Coolify.
Causa: sin bloque build:, Coolify intenta descargar delta-lms/moodle de Docker Hub, donde no existe.
Solución: moodle-cron tiene su propio bloque build: con el mismo Dockerfile. No lo quite.
Causa: detrás de Traefik (y de Cloudflare, cuando se publique con dominio), la IP de conexión no es la del usuario.
Solución: moodle-config.sh activa getremoteaddrconf=1 y reverseproxyignore con las redes de Docker y de Cloudflare. Si Cloudflare publica rangos nuevos, hay que agregarlos a esa lista en moodle-config.sh.
Arranque y despliegue
Revise el registro:
MOODLE_DB_PASSWORD (MYSQL_PASSWORD) no está definida: faltaMYSQL_PASSWORDen Coolify o en.env.no se pudo conectar a la base de datos en 5 minutos: contraseña o servidor de base incorrectos, o MariaDB no está sana.primera instalación sin MOODLE_ADMIN_PASSWORD: la base está vacía y falta la contraseña del administrador.falló la actualización de Moodle (upgrade.php): el despliegue se detuvo a propósito para no arrancar con la base a medio actualizar. La causa está en las líneas anteriores del registro.- Si falló un ajuste directo de
moodle-config.sh(fuera de unstep), el script se detiene porset -ey el contenedor no termina de arrancar.
Es normal mientras instala y configura: el control de salud tiene un margen de 15 minutos. Si sigue así después, revise el registro del servicio moodle.
Un paso de moodle-config.sh falló. El sitio arrancó igual. Busque en el registro de moodle la descripción del paso y las 25 líneas anteriores, corrija la causa y haga un Redeploy. Ver Arranque y actualizaciones.
Causa: verify-patches.php no encontró la marca de un parche importante en el archivo que modifica. Casi siempre ocurre al cambiar el commit de Moodle o de un plugin: el código cambió y el parche ya no encuentra dónde aplicarse.
Solución: volver al commit anterior en el Dockerfile o adaptar el parche (ver Desarrollo).
Causa: la imagen superó el límite de 127 capas de Docker (ocurrió con una instrucción COPY por script).
Solución: los scripts se copian en una sola capa (COPY infrastructure/moodle/*.sh ... /). No agregue un COPY por cada script nuevo.
Causa: .dockerignore es una lista blanca: lo que no está permitido ahí no entra en la imagen.
Solución: agregar la línea !infrastructure/moodle/<script> a .dockerignore y reconstruir.
Causa: las cachés de Moodle viven en moodledata, que se conserva entre despliegues y lo comparten moodle y moodle-cron. Las clases nuevas de los plugins no se encuentran con la caché vieja.
Solución: el arranque ya purga las cachés antes de configurar y al final. Si hace falta, purgue a mano:
docker exec -it delta-lms_app php /var/www/html/admin/cli/purge_caches.php(En Coolify, desde la Terminal del contenedor moodle: php /var/www/html/admin/cli/purge_caches.php.)
Causa: Coolify puede servir el tema y el JavaScript desde cachés viejas.
Solución: por eso el CSS y el JavaScript del chat de IA (y algunos ajustes de contraste) van en línea en la cabecera HTML adicional (additionalhtmlhead), que moodle-config.sh vuelve a escribir en cada arranque, y el arranque recompila el tema. Si persiste, purgue las cachés y recargue el navegador sin caché.
La clave del chat se aplica en el despliegue: cuando GROQ_API_KEY está definida, el paso crítico "Chat de IA: proveedor Groq con la clave de GROQ_API_KEY" (configure-ai-groq.php) actualiza la instancia del proveedor.
- Compruebe que
GROQ_API_KEYtiene la clave nueva en Coolify → Environment Variables y haga Redeploy. - Si el paso falla, aparece en el aviso del super administrador como paso fallido del despliegue; el detalle está en los registros del contenedor
moodle. - Si la variable no está definida, el despliegue no toca la clave guardada: se puede cambiar en Administración del sitio → Configuración IA → Ajustes técnicos, pero conviene ponerla en Coolify para que una recuperación la conserve.
Problema histórico registrado en el plan (docs/roadmap_v4.md, tarea F1.2) con varias hipótesis (caché de Apache, propiedad de los archivos de caché, caché persistente del volumen). Hoy el arranque recompila el tema (theme_reset_all_caches) y purga las cachés. Si el problema sigue ocurriendo: Por confirmar.
Cron
Sin cron no se envían correos, no se emiten certificados ni se reinicia la cuota de la IA.
-
Revise el registro de
moodle-cron(!!! [cron] ERROR). -
Si dice
upgrade pendingdurante unos minutos tras un despliegue, es normal. -
Si dice
upgrade pendingdurante 10 minutos o más, la imagen del cron no coincide con la del sitio: haga un Redeploy en Coolify (odocker compose up -d --builden local) para que ambos usen la misma imagen. -
Si dice
cron execution suspended,cron-entrypoint.shlo cuenta como fallo. La causa concreta de ese mensaje no está documentada en el repositorio: Por confirmar. Si el sitio quedó en modo de mantenimiento por un respaldo con--maintenanceinterrumpido,backup.shintenta desactivarlo siempre y, si no puede, muestra el comando para hacerlo:docker exec -u www-data <moodle> php /var/www/html/admin/cli/maintenance.php --disable
Correo (Office 365)
Revise en Correos de la Academia → Estado y prueba:
- "El correo todavía no está configurado": faltan las variables
MOODLE_SMTP_*en Coolify. - En pausa: alguien pausó los envíos (por ejemplo en una mudanza). Pulse Reanudar los envíos.
MOODLE_MAIL_DIVERT_TOdefinida: todo va a esa dirección de prueba. Déjela vacía en producción.- El tipo de correo está apagado en la pestaña Tipos de correo.
- Las notificaciones de Moodle (la campana) no salen por correo a propósito: solo salen los correos de la Academia.
El servidor no tiene permitida la salida TCP 587 hacia smtp.office365.com: casi siempre es el firewall del servidor o de la red. TI debe abrirla.
Office 365 tiene desactivado el envío con usuario y clave para la cuenta o para la empresa. El administrador de Microsoft 365 lo activa en el centro de administración: Usuarios → la cuenta → Correo → Aplicaciones de correo → SMTP autenticado.
- Vuelva a pegar la clave en
MOODLE_SMTP_PASSWORDen Coolify, en modo literal y sin espacios al inicio o al final, y haga un Redeploy. - Compruebe que
MOODLE_SMTP_USERes exactamente el usuario con el que se inicia sesión en Microsoft. - Como super administrador, en Diagnosticar la conexión escriba el usuario y la clave (no se guardan). El diagnóstico muestra el largo de la clave guardada y si tiene caracteres que Coolify o Docker pueden alterar (
$,#, comillas, barra invertida, espacios). - Si con la clave escrita también falla, el problema no es Coolify: el administrador de Microsoft 365 revisa en Microsoft Entra → Usuarios →
info@→ Registros de inicio de sesión (acceso condicional por ubicación o IP), a la hora de la prueba.
smtp.office365.com tiene direcciones IPv6 y el servidor no tiene salida IPv6. La imagen ya prefiere IPv4 (/etc/gai.conf); si aparece el error, la imagen en uso es anterior a ese ajuste: haga un Redeploy para reconstruirla.
Según el diagnóstico, suele ser un proxy o firewall que inspecciona el tráfico, o certificados raíz desactualizados en el servidor.
Office 365 acepta unos 30 correos por minuto por cuenta. Los que pasan del límite esperan en cola y salen en los minutos siguientes. Los límites por minuto (máximo 30) y por día se ajustan en Correos de la Academia → Estado y prueba → Límites de envío.
Hay dos instalaciones con los mismos datos y correo configurado (por ejemplo, una prueba de recuperación). Quite las variables MOODLE_SMTP_* de la copia de prueba o defina MOODLE_MAIL_DIVERT_TO con un buzón propio. Ver Recuperación.
Se restauró un respaldo anterior al envío de esos enlaces. Vuelva a enviarlos desde Correos de la Academia → Bienvenidas o, a una persona, desde Personal Deltamontero → Editar → Enviar el enlace por correo.
Respaldos y restauración
Hay más de una instalación en el servidor y el script no sabe cuál usar. Defina COMPOSE_PROJECT_NAME, o los contenedores con DB_CONTAINER, APP_CONTAINER y CRON_CONTAINER.
- El servicio
crondel servidor no está activo:setup-backup.shlo avisa. Actívelo consystemctl enable --now cron. - Revise
/etc/cron.d/delta-lms-backupy/var/log/delta-lms-backup.log. - Recuerde que la hora del servidor está en UTC: 2:00 de Ecuador son las 7:00 UTC.
- "hay copia externa configurada pero rclone no está instalado": instale rclone.
- "no se pudo copiar el respaldo a ...": revise las credenciales del remoto en
/root/.config/rclone/rclone.conf(si es OneDrive, el token puede haber vencido). - "no se pudieron borrar las copias externas de más de N días": es solo un aviso; el respaldo se copió.
Es a propósito: con la base vacía, el arranque de Moodle lo reinstalaría. Corrija la causa (el código de salida indica la etapa) y vuelva a ejecutar el mismo comando.
El respaldo y la imagen tienen distinta versión de Moodle. Si la imagen es más nueva, el arranque hace la actualización. Si la imagen es más vieja, no se puede: Moodle no admite bajar de versión. Construya la imagen con la versión del respaldo o una más nueva.
backup-daily.sh no encontró el contenedor de Moodle corriendo ("AVISO: Moodle no está corriendo; no se registró el estado"). El respaldo puede estar bien: revise el registro del servidor.
Accesos y hora
Los códigos dependen de la hora. El reloj del servidor estaba unos 16 minutos adelantado y sin sincronizar (NTP service: inactive). Es un contenedor de Proxmox: se corrige activando NTP en el nodo (TI). Mientras tanto, si se pierde el acceso, ver Accesos y cuentas de administración.
Misma causa: el reloj del servidor. PHP y Moodle usan la zona America/Guayaquil, pero dependen del reloj del sistema.
Diez contraseñas fallidas en 30 minutos la bloquean 30 minutos. Se desbloquea sola o la desbloquea el super administrador desde la ficha de la persona.
Lo encendió una versión anterior de la plataforma, que detectaba una contraseña de ejemplo publicada en el repositorio. Cambie la contraseña de la cuenta admin (su perfil → Cambiar contraseña, o desde la otra cuenta de super administrador): el aviso se quita solo en cuanto esa cuenta cambia su contraseña. Las contraseñas que estuvieron publicadas deben considerarse comprometidas.
Contenido
No es una falla de Moodle: el video se eliminó o se hizo privado en YouTube. Módulos → Revisar los módulos los detecta. Un error 404 significa que el video fue borrado (hay que volver a subirlo); un 401 que es privado (suele bastar con cambiarlo a "no listado"). El README del repositorio lista seis videos caídos detectados el 2026-08-26.
Las partes que controla el código se vuelven a aplicar en cada despliegue (por ejemplo, el curso de Introducción, los permisos de los perfiles o el estándar de los módulos). Para que el cambio sea permanente hay que hacerlo en el código. Ver Despliegue en producción.
Mantenimiento periódico
Qué revisar cada día, semana, mes y año para mantener la Academia sana, y qué hacer cuando cambia una clave.
Pendientes operativos
Lo que falta para cerrar la operación de la Academia Deltamontero, según el manual de recuperación y el plan del proyecto, con su estado en el código.