Arquitectura del servidor SOM
Esta página describe componentes y relaciones. No publica credenciales, tokens, claves privadas ni parámetros sensibles.
Vista general
Internet
│
▼
UFW → Nginx (TLS y enrutamiento)
├── :443 / → Moodle → PHP-FPM → PostgreSQL local
├── :443 /arqui/ y doc.minayao.site → documentación estática
├── :443 som.minayao.site → SOM Django (Docker :8000 local)
├── :443 locker.minayao.site → Learning Locker (Docker :8081 local)
├── :443 yet.minayao.site → Yet SQL LRS (Docker :8080 local)
├── :443 kuma.minayao.site → Uptime Kuma (Docker :3002 local)
└── :443 portainer.minayao.site → Portainer (Docker :9444 local)
Ollama → API privada en 127.0.0.1:11434
Docker → Portainer, Kuma, SOM, Learning Locker y Yet SQL LRS
├── SOM → PostgreSQL privado
├── Learning Locker → MongoDB y Redis privados
└── Yet SQL LRS → PostgreSQL privado
Entradas y conexiones
| Entrada | Servicio | Backend | Persistencia |
|---|---|---|---|
| minayao.site | Moodle | PHP-FPM del host | PostgreSQL host + /var/moodledata |
| som.minayao.site | SOM | 127.0.0.1:8000 | PostgreSQL app-db-1 |
| locker.minayao.site | Learning Locker | 127.0.0.1:8081 | MongoDB, Redis y archivos |
| yet.minayao.site | Yet SQL LRS | 127.0.0.1:8080 | PostgreSQL dedicado |
| kuma.minayao.site | Uptime Kuma | 127.0.0.1:3002 | Volumen uptime-kuma |
| portainer.minayao.site | Portainer | 127.0.0.1:9444 | Volumen portainer_data |
| doc.minayao.site | Esta documentación | Archivos estáticos | /opt/server-architecture |
Todos los backends Docker publicados están ligados a loopback; sus bases y cachés no publican puertos. /arqui/, :3001 y :9443 se mantienen como accesos compatibles. El nombre anterior lrs.minayao.site redirige permanentemente a yet.minayao.site.
Core del servidor
| Componente | Estado | Función y límite |
|---|---|---|
| Nginx 1.24 | Activo | Único punto de entrada, TLS y proxy inverso. |
| Moodle 5.2.1 | Activo | LMS instalado en el host; raíz pública separada y datos persistentes. |
| PHP-FPM 8.3 | Activo | Ejecuta Moodle mediante socket Unix local. |
| PostgreSQL 16.14 | Activo | Datos de Moodle; escucha sólo en localhost con autenticación SCRAM. |
| Ollama 0.32.6 | Activo | IA privada; API sólo en localhost, sin exposición pública. |
| SOM Django | Saludable | Monolito modular en Docker, publicado exclusivamente bajo /som/. |
| PostgreSQL SOM 16.14 | Saludable | Base privada en la red interna de SOM, sin puerto publicado. |
| Learning Locker 7.1.1 | Saludable | LRS en Docker con xAPI Service 7.1.2, MongoDB y Redis privados. |
| Yet Analytics SQL LRS 0.9.7 | Saludable | LRS en Docker con PostgreSQL privado y volumen dedicado. |
Moodle conserva su código, directorio de datos y base. SOM debe integrarse mediante web services, eventos o una capa puente; no escribiendo directamente en tablas internas de Moodle.
Plataforma Docker
| Servicio | Backend local | Persistencia | Entrada |
|---|---|---|---|
| Uptime Kuma | 127.0.0.1:3002 | Volumen dedicado | HTTPS :3001 vía Nginx |
| Portainer | 127.0.0.1:9444 | Volumen dedicado | HTTPS :9443 vía Nginx |
| SOM Django | 127.0.0.1:8000 | Imagen reproducible | HTTPS /som/ vía Nginx |
| PostgreSQL SOM | Red interna :5432 | app_postgres_data | Sin entrada pública |
| Learning Locker | 127.0.0.1:8081 | Cinco volúmenes dedicados | HTTPS locker.minayao.site |
| MongoDB y Redis de Learning Locker | Red interna | Volúmenes dedicados | Sin entrada pública |
| Yet SQL LRS | 127.0.0.1:8080 | yet-lrsql-postgres-data | HTTPS yet.minayao.site |
| PostgreSQL de Yet SQL LRS | Red interna :5432 | Volumen dedicado | Sin entrada pública |
Portainer controla el socket Docker y debe considerarse una consola administrativa. SOM, Learning Locker y Yet SQL LRS disponen de manifiestos Compose reproducibles. Los servicios usan redes privadas, volúmenes identificables y políticas de reinicio; sólo Nginx publica las entradas externas.
Plataformas LRS
Learning Locker
El proyecto Compose learning-locker se administra desde /opt/docker-projects/locker/compose.yaml. Incluye MongoDB con replica set, Redis, migraciones, API, interfaz web, worker, scheduler, xAPI Service y un proxy Nginx interno. El host sólo publica 127.0.0.1:8081; Nginx termina TLS en locker.minayao.site.
Los datos sobreviven a recreaciones y reinicios en cinco volúmenes dedicados: MongoDB, configuración de MongoDB, Redis, archivos de aplicación y almacenamiento xAPI. Los servicios continuos usan restart: unless-stopped. Learning Locker 7.1.1 contiene componentes fuera de soporte y debe permanecer aislado, respaldado y accesible sólo mediante TLS.
locker.minayao.site → Nginx host → 127.0.0.1:8081 → Nginx del stack
├── ui
├── api
└── xapi
api/ui → MongoDB worker/scheduler → Redis y tareas asíncronas
| Contenedor | Responsabilidad | Dato o límite |
|---|---|---|
| mongo | MongoDB 4.4.29 con replica set | Dos volúmenes; 27017 no publicado |
| mongo-init / migrate | Inicialización y migraciones puntuales | No son daemons permanentes |
| redis | Coordinación y colas | Volumen propio; sin puerto público |
| api / ui | API de gestión e interfaz | Almacenamiento compartido persistente |
| worker / scheduler | Trabajo asíncrono y programado | Sin entrada web |
| xapi | xAPI Service 7.1.2 | Volumen xAPI propio |
| nginx | Proxy del stack | Único puerto publicado: loopback 8081 |
La red learning-locker_locker-internal no tiene el atributo Docker internal: true; el aislamiento de datos se basa en que sólo el proxy publica un puerto.
Yet Analytics SQL LRS
El proyecto Compose yet-lrsql se administra desde /opt/docker-projects/yet/compose.yaml. SQL LRS escucha en 127.0.0.1:8080 y Nginx lo publica en yet.minayao.site. PostgreSQL permanece exclusivamente en la red privada yet-lrsql-internal.
PostgreSQL conserva sus datos en yet-lrsql-postgres-data. Ambos contenedores tienen health checks y restart: unless-stopped. La administración está bajo /admin y el endpoint xAPI bajo /xapi.
yet.minayao.site → Nginx host → 127.0.0.1:8080 → SQL LRS
└── PostgreSQL :5432
lrsql usa yetanalytics/lrsql:v0.9.7 y guarda su estado durable en PostgreSQL 16.15 Alpine. Sólo la aplicación publica loopback; la base vive en yet-lrsql-internal y no publica 5432. La red tampoco usa internal: true, por lo que la ausencia de puertos publicados es el límite comprobado.
SOM: monolito modular desplegado
SOM Django
├── API y autenticación
├── integración Moodle
├── identidad
├── LRS y eventos
├── instructores
├── analítica
└── integración IA/Ollama
La entrada activa es https://169.58.128.68/som/api/.... Nginx envía exclusivamente /som/ al contenedor Django enlazado a loopback.
El arranque espera a PostgreSQL, aplica migraciones, recopila estáticos e inicia Gunicorn con dos workers. Django y PostgreSQL tienen health checks. PostgreSQL vive sólo en la red interna; Django utiliza además una red con salida para futuras integraciones.
| Ruta | Estado |
|---|---|
/som/ | Interfaz disponible |
/som/api/health/ | Salud pública, JSON 200 |
/som/api/ | API REST navegable |
/som/lrs/ | Módulo autenticado |
/som/admin/ | Administración Django |
/som/static/ | Estáticos mediante WhiteNoise |
Los módulos deberían extraerse sólo cuando exista una necesidad medible: escalado independiente, aislamiento de fallos, despliegues diferentes o propiedad por equipos separados.
Operación y administración
Uptime Kuma
Contenedor único, imagen mayor 2, health check y reinicio automático. Su configuración está en el volumen uptime-kuma. Nginx publica 127.0.0.1:3002 mediante el subdominio; HTTPS :3001 continúa por compatibilidad.
Portainer
Contenedor único con estado en portainer_data, publicado en loopback 9444 y mediante su subdominio. Monta el socket Docker, de modo que es una consola privilegiada equivalente al control de contenedores. Tiene reinicio automático, pero no health check declarado.
Documentación
No usa Docker. Nginx sirve esta misma carpeta tanto en doc.minayao.site como bajo /arqui/; el Markdown canónico es único, evitando documentación divergente.
Orden de subdominios y casos de fallo
El DNS comodín hace que incluso un subdominio inexistente llegue a este servidor. Cada servicio válido tiene un server_name explícito y Nginx dispone ahora de servidores por defecto para HTTP y HTTPS. Un host desconocido conserva su ruta, pero redirige con 301 a https://minayao.site; ya no puede caer por orden de carga en Learning Locker. Los desafíos ACME quedan exceptuados para permitir la renovación TLS.
Límites recomendados
- Nginx controla toda exposición pública y TLS.
- Moodle se consume mediante contratos API explícitos.
- Ollama permanece privado detrás de una interfaz interna controlada.
- Cada servicio es propietario de sus datos, volúmenes y credenciales.
- Los trabajos largos de analítica salen del ciclo de petición HTTP.
- Eventos y tareas asíncronas pueden introducirse antes de separar microservicios.
Pendientes prioritarios
- Definir y probar respaldos de PostgreSQL, Moodledata, configuraciones y volúmenes Docker.
- Restringir el acceso administrativo a Portainer.
- Revisar los límites PHP de carga frente al límite configurado en Nginx.
- Convertir Portainer y Kuma en proyectos Compose reproducibles; SOM ya dispone de manifiesto.
- Definir y probar respaldos de los volúmenes de Learning Locker y Yet SQL LRS.
- Mantener las bases de datos y cachés de los LRS sin puertos publicados.
- Mantener SOM publicado exclusivamente bajo
/som/. - Diseñar el acceso privado y auditable de SOM a Ollama.