Ir al contenido
El escritorio de Jorge Saurina, con tres monitores y uno vertical arriba
El escritorio en ángulo, con la planta y la estantería iluminada
El estudio de noche, visto desde el sillón
Sitios Web

Quité el CMS de mi sitio y ahora el contenido son archivos de texto

Mi sitio personal corría sobre un Strapi con base de datos para servir cinco páginas que casi nunca cambiaban. Esto es lo que encontré al abrirlo después de dos años y lo que hice con él.

Monograma JS de Jorge Saurinapor Jorge Saurina
La portada de jopsa.me tras la reconstrucción, con la foto del escritorio a la izquierda

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.