Abrí el proyecto de mi sitio personal después de dos años sin tocarlo. Lo primero que vi no fue el código: fue la lista de procesos del servidor. Dos aplicaciones corriendo, una base de datos MySQL, un subdominio para el panel de administración y un dominio principal que, según cómo llegaras, respondía con un error 500.
Todo eso para servir cinco páginas que no habían cambiado desde 2023.
Lo que había
La versión anterior era un Next.js 13 que consumía una API de Strapi. El CMS vivía en strapi.jopsa.me con su base de datos, y el frontend en otro proceso. Sobre el papel, la arquitectura correcta: un panel para editar contenido sin tocar código.
En la práctica, en dos años entré al panel unas tres veces.
El error 500 lo encontré por casualidad, entrando desde una herramienta que no manda la cabecera Accept-Language. El middleware daba por hecho que siempre llegaba, y sin ella reventaba. Llevaba meses así, devolviendo un error a cualquier bot o cliente que no la enviara. Nadie me avisó, claro: los errores de un sitio personal no los reporta nadie.
La pregunta
Antes de reescribir nada me hice una sola pregunta: ¿qué me está dando el CMS que no me daría un archivo de texto?
La respuesta honesta fue nada. No hay redacción, no hay flujo de aprobación, no hay veinte editores. Hay una persona que escribe, y esa persona sabe usar git. Lo que sí me estaba dando el CMS era una base de datos que respaldar, un proceso más que vigilar, una versión que actualizar y una superficie de ataque extra.
Lo que hice
Reescribí el sitio con el contenido en archivos: YAML para las páginas y Markdown para los artículos, uno por idioma. Cada archivo se valida contra un esquema al arrancar, así que un campo mal escrito rompe el build en mi máquina y no en producción.
Las páginas se componen con bloques. Cada bloque es un tipo declarado en el esquema y un componente en el código; el contenido nunca invoca un componente arbitrario. Añadir una sección nueva son dos cosas: describir su forma y pintarla.
El resultado son 22 rutas generadas en el build. Sin base de datos, sin CMS, sin consultas en tiempo de respuesta.
Los dos tropiezos que me costaron una tarde
El servidor no podía compilar. El VPS corre Rocky Linux 8, con una glibc de 2018, y el compilador de Next 16 pide una más nueva. En vez de pelearme con el sistema, moví el build a GitHub Actions: ahí se compila un bundle autocontenido, se sube por rsync y se reinicia el proceso. Cada push a la rama principal despliega solo, después de pasar lint, tipos, pruebas y validación del contenido.
Un bucle de redirecciones que no existía en local. En producción, la portada entraba en un ciclo infinito entre / y /es. La causa era una variable de entorno: al fijar HOSTNAME=127.0.0.1, Next comparaba el origen de la reescritura interna con el de arranque, no coincidían, la trataba como externa y volvía a pasar por el proxy. Quitar esa línea lo arregló. Lo dejé escrito en un comentario para no volver a caer.
Lo que quedó
Un proceso en lugar de dos. Ninguna base de datos. Un despliegue que tarda dos minutos y empieza con git push. Y de paso, al retirar el stack viejo, liberé siete gigas en el servidor.
La lección no es que los CMS sean malos. Es que estaba pagando el mantenimiento de una flexibilidad que no usaba. Cuando escribo, abro el editor y hago commit; el sitio se publica solo. Para lo que necesito, es más rápido que cualquier panel.



