Registro de trabajo¶
2026-07-27 — registro del trabajo con el que se levantó esta plataforma documental, se cambió el modelo de propiedad de la configuración del edge, se cerraron los puntos débiles operativos y se tradujo toda la documentación a siete idiomas.
El propósito de esta página no es anotar qué se hizo, sino por qué se decidió así. El razonamiento es la información que envejece más despacio: el código puede cambiar, pero la justificación de una decisión permanece.
Alcance
Los detalles operativos — direcciones de host, rutas, valores secretos de configuración — no forman parte de este sitio público; viven en un runbook cerrado dentro del repositorio correspondiente.
Cinco líneas de trabajo¶
| # | Trabajo | Resultado |
|---|---|---|
| 1 | Levantar la plataforma documental | docs.gerege.mn entró en servicio |
| 2 | Descomponer la propiedad de la configuración del edge | Cada dominio pasó a su propio repositorio |
| 3 | Cerrar los puntos débiles operativos | Eliminados el borrado accidental y los puntos ciegos |
| 4 | Traducir la documentación a siete idiomas | Mongol + los seis idiomas oficiales de la ONU, cobertura completa |
| 5 | Dejar constancia del paso a Nexus | El nuevo modelo del ecosistema documentado en siete idiomas |
1. La plataforma documental¶
Qué se hizo¶
Un portal en MkDocs Material que reúne en un solo lugar la documentación a nivel de ecosistema de Gerege: 25 páginas, mongol por defecto, diagramas Mermaid, CSS de marca. La cobertura lingüística se amplió después a siete idiomas — véase la sección 4.
El contenido se recopiló de los README, los directorios docs/ y los documentos
de arquitectura de los repositorios del ecosistema, y se ordenó en cuatro partes:
capas · plataformas · estándares · operación.
Decisiones clave¶
Servir el sitio estático desde un contenedor aparte. Añadir un mount nuevo al contenedor del edge nginx obliga a recrearlo, y en ese momento todos los dominios caen un instante. Sirviéndolo desde su propio contenedor pequeño, al edge le basta con una adición de configuración y un reload.
Desplegar in situ, con rsync. El directorio del sitio se monta por bind en
el contenedor. Sustituir el directorio entero (mv) deja al contenedor mirando
todavía al inode antiguo, y el contenido nuevo no aparece nunca. rsync
actualiza los ficheros en su sitio, así que el mount sigue siendo válido.
Anclas para títulos en cirílico. El slugify estándar de la extensión toc de
Python-Markdown elimina los caracteres no ASCII: el título ## Танилт recibe
un id vacío y los enlaces internos se rompen en silencio. Se pasó al
pymdownx.slugs.slugify, que conserva el unicode.
validation.anchors activado. En MkDocs, la comprobación de anclas viene
desactivada por defecto. Sin ella, un enlace roto que apunta a #sección
supera la construcción y llega a producción. Ahora hace fallar --strict.
Todo lo que entra en docs/ se hace público. Por eso los detalles operativos
se colocaron aparte, en un directorio que no forma parte del sitio.
2. La propiedad de la configuración del edge¶
Fue el mayor cambio arquitectónico.
Cómo era antes¶
Los vhosts de todos los dominios vivían en un único fichero central. La
consecuencia: cambiar un ajuste pequeño de docs.gerege.mn obligaba a enviar un
PR a otro repositorio y esperar al despliegue de otro equipo. Propiedad difusa y
cambios lentos.
Cómo es ahora¶
el directorio de configuración del edge nginx
├── (ficheros compartidos) ← los posee el repositorio de la stack combinada
│ sso · dan · gsign · xyp
├── docs.gerege.mn.conf ← docs-gerege-mn
├── developer.gerege.mn.conf ← developer-gerege-mn
└── template.gerege.mn.conf ← template-gerege-mn
El vhost de cada dominio vive ahora en el repositorio de su servicio, y lo instala su propio despliegue. Un cambio se completa dentro de un solo repositorio.
Por qué funciona¶
El directorio de configuración está físicamente dentro de la copia de trabajo de
otro repositorio, y el despliegue de ese repositorio ejecuta git reset --hard.
Pero git reset --hard solo restaura los ficheros con seguimiento: no toca
los untracked. Así que el fichero instalado desde un repositorio ajeno
sobrevive.
Tres condiciones para ser plenamente autónomo¶
Un vhost no debe depender de los ficheros compartidos en nada:
| Condición | Por qué |
|---|---|
Su propia limit_req_zone |
Recurrir a un fichero de zonas compartido crea dependencia |
Su propio bloque listen 80 (ACME + redirección) |
Así la renovación del certificado funciona sola |
| Reinstalación en cada despliegue | Si el fichero se pierde, se restablece por sí mismo |
Un orden de migración sin interrupciones¶
- Primero instalar el fichero nuevo. En ese momento un mismo dominio queda
definido en dos sitios, pero nginx lo trata solo como un aviso
conflicting server name: el comportamiento no cambia, ambos apuntan al mismo upstream. - Después quitarlo del fichero central. La duplicidad desaparece y el fichero nuevo entra en vigor.
Si se hace al revés, el dominio cae entre los dos pasos.
Sin rutas del host en un repositorio de código abierto¶
template-gerege-mn es de código abierto, y la convención vigente era guardar
los datos del servidor solo en los secrets de la CI. Por eso el instalador
deduce él mismo la ruta del directorio de configuración a partir de los mounts
del contenedor edge:
docker inspect <edge> --format \
'{{range .Mounts}}{{if eq .Destination "/etc/nginx/conf.d"}}{{.Source}}{{end}}{{end}}'
Esto es más fiable que codificar la ruta a mano, así que después se adoptó en los tres repositorios: sigue funcionando cuando cambia el host o la ruta.
Un requisito previo de seguridad¶
PRIMERO el certificado, después el vhost. Añadir un vhost HTTPS sin
certificado hace fallar nginx -t, y en ese momento todos los dominios quedan en
riesgo. El desafío ACME funciona a través del default server general del puerto
80, así que obtener el certificado no exige cambiar la configuración.
Antes del push, la configuración final se verificó con nginx -t en un
contenedor temporal, con la red y los certificados reales.
3. Endurecimiento operativo¶
Protección frente al borrado accidental¶
Había ficheros que sostienen producción y no estaban con seguimiento en ningún
repositorio. git reset --hard no los toca, pero git clean -fd los borra.
| Fichero | Si se pierde | Solución |
|---|---|---|
| Los vhosts de tres dominios | 3 dominios caen a la vez | .gitignore |
| El override de compose del host | El contenedor se desengancha de la red edge → 502 | .gitignore + un fichero de ejemplo |
Por qué lo resuelve .gitignore: sin -x, git clean omite los ficheros
ignorados. Eso los protege sin necesidad de darles seguimiento.
El override de compose no debe llevar seguimiento: compose lo lee
automáticamente, así que la configuración de producción se impondría en el
entorno local de cada desarrollador. Por eso el fichero vivo permanece untracked
en el host y en el repositorio solo se guarda un ejemplo de restauración. Que
el ejemplo produce el mismo resultado que la configuración viva se confirmó
comparando la salida de docker compose config.
Monitorización de salud¶
Ya existía antes un script de monitorización en el host, pero coincidieron dos defectos: no estaba registrado en cron en absoluto, y algunos de los contenedores que nombraba habían cambiado de nombre y ya no existían. El script omite en silencio un contenedor ausente, así que nadie sabía que la monitorización se había detenido por completo.
Decisiones clave de la nueva versión:
El healthcheck propio del contenedor va primero. Su interval y sus retries ya están ajustados a ese servicio concreto.
El probe HTTP se hace desde dentro del contenedor. Comprobarlo todo a través del edge haría que, al caer el edge, todos los servicios parecieran caídos, lo que provocaría un reinicio masivo y ocultaría el fallo real. Ahora cada comprobación es independiente.
Umbral de fallos consecutivos más cooldown. Una demora transitoria (despliegue, GC, carga) no provoca reinicio, y un servicio realmente roto no se apaga y enciende en bucle.
No reiniciar automáticamente la infraestructura stateful. Las bases de datos y la caché solo se vigilan y se registran. Un reinicio no arregla una causa real como un disco lleno; corta las transacciones de muchas stacks y solo añade daño. En tal caso decide una persona.
Un contenedor ausente se registra como error, para no repetir el defecto principal de la versión anterior.
Umbral · cooldown · política sobre stateful · recuperación · contenedor ausente: los cinco comportamientos se verificaron de verdad en un contenedor de prueba aislado.
Renovación de certificados¶
Ver una entrada en cron no basta: que la renovación funcione de verdad se
probó con --dry-run, confirmando que todos los dominios se renuevan con éxito.
Es el tipo de riesgo que permanece callado hasta la fecha de caducidad.
4. Cobertura en siete idiomas¶
Qué se hizo¶
Todas las páginas del sitio se tradujeron a mongol más los seis idiomas oficiales de las Naciones Unidas: العربية · 中文 · English · Français · Русский · Español. La traducción inglesa era antes parcial (portada, introducción, capas, listado de plataformas, autenticación); se completó y se añadieron cinco idiomas más.
Decisiones clave¶
El mongol sigue siendo la fuente. Los otros seis son traducciones: el original se escribe en mongol y desde ahí se convierte. Con dos idiomas «fuente», el contenido empieza a divergir en silencio.
Traducir por páginas, no por idiomas. Convertir un mismo documento a seis idiomas a la vez mantiene idénticas la terminología, las filas de las tablas y la estructura. Al revés — «primero todas las páginas en inglés» — los idiomas traducidos después irían persiguiendo un texto de origen ya modificado.
La notación técnica no se tradujo. Dominios, nombres de repositorio, código, YAML, rutas de endpoints y nombres de estándares (OIDC · PKCE · RFC 3161) quedan tal cual en todos los idiomas. Traducirlos los volvería imposibles de copiar y ejecutar.
Los nombres de fichero no se traducen. Es platforms/sso.ru.md, no
платформы/sso.md. Así la ruta de la URL no cambia al pasar de idioma, y los
enlaces profundos que llegan de otros repositorios siguen funcionando.
El RTL árabe no se hizo a mano. Material reconoce el locale ar, pone
<html dir="rtl"> y voltea por sí mismo el menú y el flujo del contenido. Los
bloques de código y los diagramas ASCII se quedan en LTR — y es lo correcto,
porque los comandos y las URL pierden su sentido si se invierte la dirección.
El slugify unicode es ahora tres veces más importante. El
pymdownx.slugs.slugify que se introdujo por los títulos en cirílico sostiene
ahora también las anclas de los títulos árabes, chinos y rusos. Con el slugify
estándar se habrían roto en silencio todos los enlaces internos de seis
locales.
fallback_to_default sigue activado. Ahora todas las páginas están
traducidas, así que el fallback no se dispara; pero queda como garantía de que el
sitio seguirá completo cuando se añada una página y su traducción vaya con
retraso.
Alcance¶
Esta política se aplica a la documentación a nivel de ecosistema, es decir, solo a este sitio. La documentación técnica profunda de cada plataforma (esquemas de endpoints, referencia de SDK) se mantiene en MN + EN dentro de su propio repositorio: quien la lee es un ingeniero que ya trabaja en ese repositorio, de modo que ampliar la cobertura aportaría poco.
5. Dejar constancia del paso a Nexus (2026-08-07)¶
Qué ocurrió¶
El repositorio open-gerege-nexus se creó el 2026-08-05 y, el 08-07, la
plataforma pasó a llamarse Gerege Nexus y se trasladó a nexus.gerege.mn.
Después llegaron dos forks: sso-gerege-nexus (Gerege SSO) y eduge-mn-nexus
(eduge.mn). Como esto cambia el modelo de distribución del ecosistema, la
documentación se puso al día en los siete idiomas.
Decisiones clave¶
No se eliminó ninguna página de plataforma existente. Template, Gerege Platform, SSO y Kiosk siguen en producción. Se añadió una página nueva y las existentes llevan un aviso que indica qué estado rige. Borrar una página habría borrado la documentación de un sistema en marcha.
La capa 3 se dividió en dos generaciones. Nexus no sustituye a la Template: ambas ocupan la capa 3 a la vez. Añadir una capa nueva habría vaciado de sentido la propia regla de capas («nunca saltarse una capa»).
El proveedor OIDC propio de Nexus NO es la capa 2. Nexus lleva un proveedor OAuth2/OIDC, pero sirve a los inquilinos y clientes de terceros de ese despliegue. La vía del ecosistema para identificar a un ciudadano sigue siendo Gerege SSO. Sin decirlo, el lector concluiría que «Nexus ha sustituido al SSO».
Cada dominio se comprobó a mano. Se confirmó que nexus.gerege.mn, eduge.mn
y geregekiosk.mn están activos mediante DNS, HTTP y sus certificados TLS. De ahí
salieron dos cosas: geregekiosk.mn sirve ahora Nexus, y open.gerege.mn ha
sido retirado del certificado de ese host, así que HTTPS falla por
discrepancia de nombre.
Se corrigió una promesa caducada. La página de Template afirmaba que el autosync lleva los cambios aguas abajo a diario; esa automatización se detuvo en toda la flota el 2026-08-06. Una promesa falsa es peor que un dato ausente: el ingeniero espera que el arreglo viaje solo.
Se cerraron dos lagunas de traducción. La sección «Dominios de marca propios» del mapa de dominios faltaba por completo en las seis traducciones; ahora las siete están al mismo nivel.
Resumen de decisiones¶
| Decisión | Justificación |
|---|---|
| Sitio estático en su propio contenedor | Recrear el edge tumba todos los dominios |
rsync, no mv |
Un bind mount se queda en el inode antiguo |
| Slugify unicode | El slugify estándar destruye las anclas de los títulos cirílicos |
Activar validation.anchors |
Si no, los enlaces rotos llegan a producción |
| El vhost en el repositorio del servicio | Un cambio se completa dentro de un repositorio |
| Un vhost totalmente autónomo | Depender de un fichero compartido deja la separación sin sentido |
| Instalar antes, quitar después | Al revés, el dominio se cae |
| Deducir la ruta automáticamente | Más fiable que fijarla a mano; no deja rutas en un repo abierto |
Proteger con .gitignore |
git clean omite los ficheros ignorados |
| No dar seguimiento al override | Compose lo lee solo — la config de prod se aplicaría en local |
| Probe desde dentro del contenedor | Evita un reinicio masivo cuando cae el edge |
| No reiniciar lo stateful | Un reinicio no arregla la causa, añade daño |
| El mongol como única lengua de origen | Con dos «fuentes», el contenido diverge en silencio |
| Traducir por página, no por idioma | Terminología y estructura quedan idénticas en seis idiomas |
| No traducir código, dominios ni nombres de repos | Traducidos, dejan de poder copiarse y ejecutarse |
| No traducir los nombres de fichero | La ruta de la URL no cambia y los enlaces profundos funcionan |
Cada idioma en una subruta (/ar/) |
Con subdominios crecerían de golpe SAN · vhost · hreflang |
Deliberadamente no hecho¶
No se separaron los dominios sso · dan · gsign · xyp. Su código vive
dentro del repositorio de la stack combinada, así que el fichero central ya es
su propio repositorio. No hay motivo para separarlos.
No se añadió un mount aparte al contenedor del edge. Eso habría exigido modificar el fichero compose de la stack combinada y, además, recrear el contenedor, tumbando un instante todos los dominios.
No se forzó un índice de búsqueda en mongol. lunr.js no admite el mongol,
así que la búsqueda en el locale por defecto funciona con tokenización estándar.
Escribir un stemmer propio costaría más de lo que hoy aporta.
Ni dominio ni subdominio aparte por idioma. Rutas del tipo /ar/ y /zh/ se
resuelven con un certificado, un vhost y un despliegue. Pasar a subdominios
habría aumentado de golpe el SAN del certificado, la configuración del edge y el
hreflang.
Riesgo residual¶
Los vhosts de los tres dominios y los ficheros de override del host están
protegidos con .gitignore, pero si alguien ejecuta git clean -fdx (que sí
incluye los ficheros ignorados) se borrarán. La forma de arreglarlo es volver a
ejecutar el script de instalación del repositorio correspondiente; queda anotado
en el runbook de cada uno de los tres repositorios.