Academia Deltamontero · Documentación
Operación y mantenimiento

Despliegue en producción

Cómo se despliega la Academia con Coolify y Traefik (hoy en la red interna; publicación con Cloudflare planificada), qué variables cargar y cómo hacer un Redeploy sin riesgos.

En producción la Academia se despliega con Coolify dentro de un contenedor LXC de Proxmox de la empresa (172246). Coolify toma el repositorio de GitHub, construye la imagen con el docker-compose.yml, inyecta las variables de entorno desde su interfaz y sirve la Academia con su propio Traefik.

Hoy la Academia se usa en la red interna de la empresa, en http://192.168.0.192. La publicación en Internet con el dominio learning.deltamontero.net detrás de Cloudflare (CDN y proxy público) está planificada; todavía no está publicada.

Hoy:         red interna → http://192.168.0.192 → Traefik (de Coolify) → Moodle
Planificado: Cloudflare → learning.deltamontero.net → Traefik (de Coolify) → Moodle

Arquitectura de producción

CapaDetalle
ServidorContenedor LXC de Proxmox 172246, con Docker y Coolify dentro (las notas de arquitectura del repositorio planificaban una VM Ubuntu 22.04 LTS de 16 GB de RAM y 4+4 vCPU)
DirecciónHoy http://192.168.0.192 (red interna de la empresa)
Docker + CoolifyCoolify construye y ejecuta los servicios mariadb, moodle y moodle-cron del docker-compose.yml
TraefikEl de Coolify. El servicio traefik del repositorio no se usa en producción (solo existe en el perfil standalone)
CloudflarePlanificado: proxy activado para learning.deltamontero.net. Todavía no está publicado

El servidor de producción es un contenedor LXC de Proxmox (172246) con Coolify dentro, no la máquina virtual que planificaban las notas del repositorio. Su sistema operativo exacto y los recursos asignados: Por confirmar con TI. TI preparó además un contenedor nuevo, 12030 (Ubuntu, 4 CPU, 8 GB de RAM, 4 GB de swap, 250 GB de disco, 192.168.0.191, nesting=1), al que se planea mudar la Academia como prueba de recuperación con datos reales (ver Recuperación).

Crear el recurso en Coolify

Recurso desde el repositorio privado

En Coolify se crea un recurso que apunta al repositorio de GitHub (privado) y usa el docker-compose.yml de la raíz. Los servicios moodle y moodle-cron tienen bloque build: con el mismo Dockerfile: así Coolify sabe que la imagen delta-lms/moodle:4.5 se construye ahí y no intenta descargarla de Docker Hub (donde no existe).

El nombre exacto del tipo de recurso y de las opciones de Coolify depende de su versión: Por confirmar en la instancia de la empresa.

Variables de entorno

Se cargan en Coolify → Environment Variables (el .env no existe en el servidor). Como mínimo:

VariableValor en producción
MYSQL_ROOT_PASSWORD, MYSQL_PASSWORDContraseñas largas (el .env.example recomienda 20 caracteres o más para MYSQL_PASSWORD)
MOODLE_WWWROOTHoy http://192.168.0.192, exactamente. Al publicar con dominio (planificado): https://learning.deltamontero.net
MOODLE_ADMIN_PASSWORDSolo cuenta en la primera instalación
MOODLE_BACKUP_ADMIN_PASSWORDCrea una vez la cuenta de respaldo admin.respaldo
GROQ_API_KEYClave del chat de IA
MOODLE_SMTP_*, MOODLE_SUPPORT_EMAILCorreo saliente con Office 365 (ver Recuperación)

La lista completa está en Variables de entorno.

Las claves con caracteres especiales ($, #, comillas, barra invertida, espacios) deben guardarse en Coolify en modo literal (sin interpolar). Si no, Coolify o Docker pueden alterarlas y, por ejemplo, Office 365 rechaza la clave del correo con el código 535.

Dominio y HTTPS

Hoy la Academia se sirve sin dominio, por la IP de la red interna (http://192.168.0.192). Cuando se publique con dominio (planificado), el dominio se configura en Coolify (Domains del servicio moodle), no en el docker-compose.yml. Coolify genera solo las reglas de su Traefik y el certificado SSL lo obtiene Traefik con Let's Encrypt.

No agregue etiquetas (labels) de Traefik manuales al servicio moodle. Si conviven con las que genera Coolify, Traefik ve dos servicios para el mismo router, no puede enlazarlos y el sitio responde 502 Bad Gateway. Las etiquetas del repositorio están comentadas a propósito y solo se reactivan para la recuperación sin Coolify.

Cloudflare (planificado)

Todavía no aplicado. Lo planificado: en Cloudflare, learning.deltamontero.net apuntará al servidor con el proxy activado. Cloudflare envía la cabecera X-Forwarded-Proto: Traefik debe propagarla, no sobrescribirla.

El modo SSL de Cloudflare (el plan propone Full strict con un certificado de origen de Cloudflare) y la restricción del firewall del servidor a las IP de Cloudflare: Por confirmar (ver Pendientes operativos).

Primer despliegue

Se lanza el despliegue. El primer arranque instala Moodle y aplica toda la configuración: tarda varios minutos. Coolify muestra cada servicio como healthy cuando:

  • moodle: la página de ingreso responde con 200 o una redirección 30x.
  • moodle-cron: el cron de Moodle se ejecutó bien en los últimos 10 minutos.

Ambos controles tienen un margen de arranque de 15 minutos.

MOODLE_WWWROOT debe ser exacto

MOODLE_WWWROOT tiene que coincidir exactamente con la dirección que ve el usuario final: hoy http://192.168.0.192 (sin barra final); cuando se publique con dominio, https://learning.deltamontero.net (con https, sin barra final). Un desajuste provoca bucles de redirección y fallas en los tokens.

Cómo se usa:

  • write-config.sh la escribe en config.php como wwwroot.
  • Si empieza por https://, activa sslproxy (el cifrado lo terminan Cloudflare y Traefik y Moodle recibe HTTP). Con la dirección actual, que empieza por http://, sslproxy queda en false.
  • reverseproxy queda siempre en false: Traefik no cambia el encabezado Host y con reverseproxy=true Moodle falla con reverseproxyabused.
  • La IP real de cada persona se toma de X-Forwarded-For, ignorando las IP internas de Docker y las de Cloudflare (ajustes getremoteaddrconf y reverseproxyignore en moodle-config.sh).

Hacer un Redeploy

Cada cambio en el repositorio llega a producción con un Redeploy en Coolify. Qué ocurre:

  1. Coolify construye la imagen de nuevo (en la prueba registrada, unos 11 minutos). Si un parche importante no quedó aplicado, la construcción falla y se ve en Coolify.
  2. Se recrean moodle y moodle-cron con la imagen nueva. Los volúmenes mariadb_data y moodledata se conservan.
  3. moodle ejecuta upgrade.php: si falla, el despliegue se detiene y el error queda en el registro.
  4. moodle-config.sh vuelve a aplicar toda la configuración. Si un paso falla, el sitio arranca igual y el super administrador ve el aviso en Moodle.

Durante unos minutos el cron puede decir upgrade pending mientras el sitio termina de actualizarse: es normal. Si sigue así más de 10 minutos, ver Solución de problemas.

No haga un Redeploy mientras se ejecuta una restauración con restore.sh.

Después de un Redeploy

  • Revise que moodle y moodle-cron estén healthy.
  • Entre como super administrador y revise el recuadro Avisos para el super administrador (pasos del despliegue que fallaron).
  • Si la versión cambió los scripts de respaldo, vuelva a copiarlos al servidor (la misma línea de activación de Respaldos).

Lo que se conserva y lo que se reescribe

Lo que se configura desde las pantallas de Moodle se conserva en cada despliegue: reglas de los repasos, calificaciones, pruebas técnicas, códigos, equipos, personal, módulos creados, el avance de todos y los cambios hechos a mano en logos, plantilla del certificado, nombres de cursos y temas, textos personalizados y nivel de IA de cada persona.

Lo que el código controla se vuelve a aplicar: ajustes del sitio, aspecto y textos de la Academia, estándar de los módulos, permisos de los perfiles según el manual, bloqueo de certificados, límites del chat de IA y el contenido del curso de Introducción (manual de la Academia). Un cambio manual en esas partes se pierde en el siguiente despliegue: para que sea permanente se cambia el código (ver Desarrollo).

Recuperación sin Coolify (perfil standalone)

Si algún día hay que levantar la Academia sin Coolify, el repositorio trae un Traefik propio en el perfil standalone:

docker compose --profile standalone up -d

Configuración en infrastructure/traefik/:

ArchivoContenido
traefik.ymlEntradas web (:80, redirige a HTTPS) y websecure (:443), proveedor Docker con exposedByDefault: false en la red delta_network, proveedor de archivos en /etc/traefik/dynamic, panel desactivado, registro de accesos
dynamic/moodle.ymlMiddleware moodle-headers (fija X-Forwarded-Proto: https, agrega X-Frame-Options, X-Content-Type-Options y Referrer-Policy) y moodle-ratelimit (100 peticiones de promedio, ráfaga de 50, contadas por la cabecera CF-Connecting-IP)

Para usarlo hay que reactivar las etiquetas comentadas del servicio moodle en docker-compose.yml (con TRAEFIK_HOST como dominio).

traefik.yml no define cómo se obtiene el certificado TLS para la entrada websecure. En una recuperación sin Coolify, la configuración del certificado es Por confirmar. No aplique el middleware compress a Moodle: puede corromper las respuestas JSON que usa la app móvil.

El procedimiento completo de recuperación está en Recuperación.

En esta página