¿De verdad necesita este blog WordPress y Kubernetes? Un experimento con Hugo, cifras reales y lo que costaría migrar

He reconstruido parte de este blog con Hugo y lo he comparado con WordPress sobre K3s: velocidad, hardware, parches, seguridad, Grafana, roles de Ansible y esfuerzo de migración. La decisión sigue abierta.

Browser showing the Hugo test copy of the blog, with an arrow labelled Test Migration from the WordPress logo to the Hugo logo and a Proof of Concept badge

🌐 También en: English · Deutsch · Français

Actualización del 6 de noviembre de 2026: ya está decidido y hecho: este blog funciona ahora con Hugo. Lo que ocurrió está aquí.

En resumen: este blog es sobre todo texto e imágenes, pero funciona sobre Kubernetes con una base de datos, un pool de PHP, una caché y diez plugins. Así que reconstruí una parte como sitio estático con Hugo y comparé ambos. El resultado me sorprendió en los dos sentidos: para los lectores, la ganancia de velocidad es menor de lo esperado; para la operación, la ganancia es mucho mayor. No hay nada decidido. Este blog sigue funcionando con WordPress.

En el pasado, Hugo me parecía demasiado engorroso, demasiado laborioso y poco fácil de usar, tanto en el día a día como para migrar desde WordPress. Con una asistencia de IA rápida, eso ha cambiado por completo: la conversión, el tema y los scripts de comprobación de esta prueba surgieron en poco tiempo. Por eso vuelvo a plantearme la pregunta.

Este artículo reúne todo lo que quiero saber antes de decidir: mediciones, estimaciones claramente señaladas, el efecto sobre cada rol de Ansible, Grafana, SELinux, la cuestión de un repositorio nuevo, el esfuerzo real y una lista de comprobación por si me decido.

Índice

🧒 Para quienes no son de TI: ¿cuál es la diferencia?

WordPress construye una página cuando alguien la pide: un programa lee el texto de una base de datos y monta la página, y una caché guarda el resultado durante un tiempo. Hugo construye todas las páginas una sola vez, por adelantado, en mi propio equipo. Después, el servidor solo entrega archivos ya terminados. No se ejecuta ningún programa para el visitante, no hay base de datos ni página de inicio de sesión que atacar.

El precio: ya no hay un editor cómodo en el navegador. Un artículo es un archivo de texto, y publicar significa construir y subir.

Lo que queda: WordPress es un programa en marcha que sirve páginas. Hugo es una herramienta que produce archivos. Casi todas las diferencias de este artículo se derivan de eso.

🧪 El experimento: tres artículos, todas las páginas, cuatro idiomas

Convertí a Markdown los tres últimos artículos y todas las páginas estáticas en inglés, alemán, francés y español, y escribí un pequeño tema con los mismos colores, las mismas fuentes y la misma estructura. Un artículo tiene ahora este aspecto en el disco:

---
title: 'HTTP/3 para mi blog y Nextcloud'
slug: http-3-para-mi-blog-y-nextcloud
date: '2026-11-03T19:59:27+01:00'
translationKey: wp3277
categories: [DevSecOps]
image: img/2026_11_no_http3.webp
---

**Actualización del 4 de noviembre de 2026:** HTTP/3 vuelve a estar desactivado en todos mis servidores.

Para un lector, se comporta igual: mismo menú, banderas de idioma, cinta de titulares, carrusel, lista de artículos, barra lateral, índice y búsqueda. Las pequeñas diferencias solo se ven comparando lado a lado. El tema es una reconstrucción mía y no una copia del tema de WordPress, así que algunos píxeles varían.

Un aspecto parecido demuestra poco. Por eso, un script comparó cada página con el original:

ComprobadoResultado
Páginas comparadas con el original de WordPress28 de 28, texto idéntico
Bloques de código, carácter por carácter24, ninguna diferencia
Tablas, títulos, elementos de lista20, 251 y 300, cantidades idénticas
Enlaces en el texto de los artículos84, todos correctos
Direcciones, canonical, hreflang, noindexIdénticos en las 28 páginas
Referencias internas de todo el sitio generado7.740 en 225 archivos HTML, 0 rotas
Tiempo de construcción1,9 s la primera vez, luego 0,14 s
Tamaño del tema y las herramientas561 líneas de tema, 217 líneas de Python

La prueba también encontró los errores que la justifican. Hugo sustituía en silencio los enlaces tel: de mi aviso legal por #ZgotmplZ. Los archivos mensuales de otros idiomas acababan en la ruta inglesa. Mi primera versión mostraba la meta descripción en lugar del extracto real. Y el logotipo estaba invertido. Solo el script de comparación encontró el primer error; yo nunca habría pulsado un enlace de teléfono.

Lo que queda: una migración vale lo que vale su comparación automática. Un sitio que parece correcto puede tener contenido roto.

⚡ Velocidad: lo que he medido y lo que solo estimo

Primero las mediciones. Se hicieron desde mi servidor doméstico contra el blog real, con 14 peticiones por línea, midiendo el tiempo hasta el primer byte. Un archivo estático en el servidor real representa lo que entregaría un sitio con Hugo.

PeticiónMedianaRango
Archivo estático57 ms50–59 ms
Portada desde la caché de páginas de WordPress58 ms55–62 ms
Artículo desde la caché de páginas de WordPress60 ms56–63 ms
Mismo artículo, generado por PHP (sin caché)146 ms134–163 ms

Esa es la sorpresa: una página de WordPress en caché es tan rápida como un archivo estático. La caché ya hace su trabajo. La diferencia solo aparece cuando la caché no actúa.

La ganancia es más clara en lo que el navegador debe descargar, sin contar imágenes y fuentes:

Portada, comprimidaWordPressHugoCambio
HTML19,4 KB4,9 KB−75 %
CSS8 archivos, 67,7 KB1 archivo, 3,6 KB−95 %
JavaScript16 archivos, 111,1 KB1 archivo, 1,0 KB−99 %
Total25 archivos, 198 KB3 archivos, 9,5 KB−95 %

Ahora, las estimaciones. Son mis expectativas, no mediciones. Todavía no he hecho una prueba real en un navegador y en condiciones realistas.

SituaciónGanancia esperadaBase
Página ya en la caché de WordPressAproximadamente 0 %Medido: 57 frente a 58 ms
Página fuera de la cachéAlrededor de un 60 % menos de espera, unas 2,5 veces más rápidoMedido: 146 frente a 57 ms
Primera visita desde el móvil con conexión regularAlrededor de un 20–40 % más rápido hasta que la página se puede usarEstimación a partir de un 95 % menos de CSS y JavaScript
Siguientes páginas de la misma visitaPequeñaLos archivos ya están en la caché del navegador
Pico de tráficoMucho más robustoSin límite de workers ni base de datos de por medio

Lo que queda: la velocidad por sí sola no justificaría una migración. Un WordPress con buena caché ya es rápido. El lector gana sobre todo porque descarga menos código, en especial en el móvil.

🖥️ Hardware: lo que el servidor necesitaría de verdad

Estos son los valores actuales del servidor del blog y mi estimación para un sitio estático. Grafana y toda la monitorización se mantienen en ambos casos, porque quiero conservarlas.

ValorWordPress sobre K3s (medido)Hugo (estimación)
CPU4 núcleos, carga de unos 0,21–2 núcleos
Memoria en uso2,7 GB de 7,5 GBUnos 1,0–1,2 GB
Tamaño de servidor razonable4 GB o más2 GB
Datos de Kubernetes en el disco7,1 GB0
Sitio en el disco375 MB de aplicación y mediosMenos de 500 MB para todos los artículos
Pods en marcha / imágenes de contenedor17 / 140 / 0
Tarea de fondo cada pocos minutoswp-cronNinguna
Reglas de cortafuegos (salida de nftables)7.760 líneas, sobre todo de K3sUnos cientos de líneas

Así se reparte hoy la memoria, por proceso. Estos valores se solapan, de modo que su suma supera el consumo real:

ParteMemoriaCon Hugo
k3s-server847 MBDesaparece
containerd y sus shims383 MBDesaparece
php-fpm349 MBDesaparece
MariaDB249 MBDesaparece
Ingress (nginx y controlador)316 MBSustituido por un nginx pequeño
Grafana357 MBSe queda
Alloy273 MBSe queda
Loki179 MBSe queda
Prometheus175 MBSe queda

Lo que queda: el sitio en sí apenas necesitaría nada. Con alrededor de 1 GB, la monitorización sería lo más grande del servidor y marcaría su tamaño mínimo.

📅 Trabajo diario y parches

Desde el 1 de septiembre, este repositorio ha recibido 256 commits, y 76 de ellos tocaban los tres grandes roles del blog. No todo es mantenimiento, porque buena parte fue construcción. Aun así, muestra adónde va la atención. El día de actualizaciones y las dos vulnerabilidades de PHP en un día son buenos ejemplos de lo que esto significa en la práctica.

TareaWordPress sobre K3sHugo
Actualizaciones del sistemaSíSí
K3s, Helm, ingress, cert-managerSíDesaparece
WordPress, 10 plugins, temaSí, automático con comprobacionesDesaparece
PHP, incluidos parches de urgenciaSíDesaparece del servidor
MariaDB y RedisSíDesaparece
Versiones fijadas para el blog9 de 30 entradas, más la pila común de K3snginx del sistema, Hugo en mi equipo
Análisis nocturno de imágenes y sus hallazgosSí, véase TrivyDesaparece; quedan los paquetes del sistema
Alertas de workers, pods, base de datosSíDesaparece
Vaciar cachés tras un cambioCaché de páginas, de objetos y de optimizaciónDesaparece
Leer correos de monitorización y seguridadSíSí, con muchos menos motivos
Escribir un artículoEditor en el navegadorArchivo de texto, Git, construir, subir
Si una actualización rompe algoEl sitio real puede caerFalla la construcción, el sitio sigue igual
Marcha atrásVolcado de base de datos y restaurar archivosSubir la construcción anterior

Los Nextcloud siguen en K3s, así que mi día de actualizaciones no desaparece. Solo se acorta.

Lo que queda: esta es la verdadera ganancia. Desaparecen clases enteras de actualizaciones, urgencias y alertas, porque ese software ya no existe en el servidor.

🔐 Seguridad: una valoración honesta

Esta valoración es mi opinión, no una medición. «Alto» significa aquí riesgo alto.

AmenazaWordPress sobre K3sHugoPor qué
Vulnerabilidad en plugin o núcleoMedio a altoNingunoNo se ejecuta código en el servidor
Ejecución remota de código en PHPMedioNingunoSin PHP
Inyección SQLBajo a medioNingunoSin base de datos
Robo de acceso de administradorBajo, gracias a 2FA y filtro geográficoNingunoNo hay acceso web
Pérdida de datos tras una intrusiónMedioBajoSin datos de usuarios; basta una reconstrucción limpia
Vulnerabilidad de nginxMedioMedioSe mantiene
Núcleo o sistema operativoMedioMedioSe mantiene
SSH o clave de despliegueBajoBajo a medioLa clave de despliegue pasa a ser el secreto valioso
Cadena de construcción (Hugo, tema, mi equipo)No aplicaBajo a medioNuevo: se publicaría una construcción envenenada
Acceso a GrafanaBajo a medioBajo a medioSe mantiene y pasa a ser el mayor objetivo web
Kubernetes como superficie de ataqueBajo a medioNingunoSin servidor de API

Dos puntos incómodos. Primero, «estático» no significa «seguro»: el servidor, SSH, nginx y el DNS requieren el mismo cuidado, y mis nueve capas de defensa no dejan de tener sentido. Segundo, con Grafana el servidor no es puramente estático. Sigue habiendo un acceso, y es el que merece más atención.

Lo que queda: la superficie de ataque se reduce mucho, porque varias clases de ataque ya no tienen nada a lo que apuntar. Los riesgos restantes se trasladan a la clave de despliegue y a Grafana.

🧱 ¿Sigo necesitando K3s en el servidor del blog?

Técnicamente, no. El artículo a fondo sobre K3s y el artículo sobre WordPress en Kubernetes explican por qué lo elegí. Un solo nginx con una carpeta de archivos no necesita orquestador. Pero K3s tiene ventajas que perdería de verdad:

AspectoCon K3sSin K3s
Memoria y disco➖ Unos 1,2 GB de RAM y 7,1 GB de disco➕ Nada
Piezas móviles➖ Servidor de API, kubelet, containerd, CNI, ingress, cert-manager➕ Un servicio
Cortafuegos➖ K3s añade miles de líneas; hay que tener cuidado en cada cambio➕ Solo mis reglas
Actualizaciones➖ K3s, charts e imágenes➕ Paquetes del sistema
Alta disponibilidad➖ Ninguna con un solo nodo➖ Tampoco
Aislamiento entre partes➕ Pods, NetworkPolicies➖ Apenas necesario con un servicio
Actualizaciones sin corte➕ Actualizaciones progresivas incluidas➕ Sustituidas por un cambio atómico de carpeta
Mismas herramientas que en los Nextcloud➕ Una forma de trabajar➖ Dos formas de trabajar
Banco de pruebas para los Nextcloud➕ Servidor pequeño que recibe K3s primero➖ Se pierde; lo tendría que sustituir una VM de pruebas
Valor de aprendizaje y material para el blog➕ Alto➖ Menor en este servidor

Los Nextcloud son otro caso: PHP, Collabora, push y tareas cron son realmente varios servicios que trabajan juntos.

Lo que queda: en el blog, K3s ya no se justifica por necesidad técnica, sino por uniformidad, pruebas y aprendizaje. Son razones legítimas, pero conviene llamarlas por su nombre.

📝 Lo que sigue justificando WordPress

Sería fácil descartar WordPress aquí. Sería un error, porque resuelve problemas reales que Hugo no resuelve:

Punto fuerte de WordPressCon Hugo
Editor en el navegador, utilizable por cualquieraEditor de texto y Git, o una herramienta CMS adicional
Escribir y publicar desde el móvilIncómodo sin herramientas adicionales
Biblioteca de medios con subida y búsquedaArchivos en una carpeta
Varios autores con rolesSolo mediante Git o una herramienta adicional
Comentarios y formulariosHace falta un servicio externo
Publicación programadaSolo con una construcción programada
Plugins para casi todoHay que hacerlo uno mismo
Análisis SEO mientras se escribe (Yoast)Metaetiquetas sí, análisis en directo no
Traspaso a una persona no técnicaCasi imposible
Tienda, miembros, contenido dinámicoNo es la herramienta adecuada

Esto es en lo que se convertirían los plugins actuales:

PluginCon Hugo
PolylangIncluido en Hugo
Yoast SEOPlantillas propias: títulos, meta, Open Graph, schema, sitemap. Schema más simple, sin análisis en el editor
Easy Table of ContentsIncluido en Hugo
AutoptimizeIncluido en Hugo (minify)
CompressXProcesado de imágenes de Hugo al construir
WP Super Cache, Redis CacheNo hacen falta
Two Factor, Limit Login AttemptsNo hacen falta sin acceso
Classic EditorNo aplica

También hay un aspecto personal. La mayoría de mis últimos artículos se crean con ayuda de la IA, por lo que el editor cómodo me importa menos que a la mayoría de los blogueros. Con un archivo Markdown y un commit de Git, trabajar con un asistente de IA sería incluso más sencillo que hoy. Tampoco quedaría atado a él: Markdown se edita con cualquier editor de texto.

Lo que queda: WordPress sigue siendo la opción correcta cuando escriben otras personas, cuando se publica sobre la marcha o cuando el sitio hace algo más que mostrar contenido. Solo es la herramienta equivocada si nada de eso se aplica.

📈 ¿Cuántos sitios con WordPress, cuántos con Hugo?

En el mercado, Hugo es un nicho pequeño. Según W3Techs, a 5 de noviembre de 2026:

IndicadorWordPressHugo
Cuota de todos los sitios web39,5 %0,1 %
Cuota de sitios con CMS conocido58,2 %0,2 %
Proporción sobre todos los sitiosAlrededor de 400 : 11
Estrellas en GitHub21.519 (un espejo; el desarrollo se hace en otro lugar)90.379
LicenciaGPLApache 2.0

Estas cifras deben leerse con cautela. W3Techs da cuotas y no números absolutos, y no siempre reconoce los sitios estáticos, así que Hugo probablemente esté infravalorado. Las estrellas miden el interés entre desarrolladores, no los sitios en funcionamiento, y el repositorio de WordPress es solo un espejo. No conviene comparar directamente ambos valores.

Aun así, las cifras muestran algo: millones de personas usan WordPress sin haber visto nunca un repositorio de Git, mientras que Hugo tiene una comunidad inusualmente grande para su cuota de mercado. Mi impresión, sin datos sólidos: quienes toman este camino son sobre todo los más frikis, y por motivos que encajan con este artículo: sin PHP, sin base de datos, sin acceso, poca superficie de ataque, Markdown y Git en lugar de una interfaz web. Un sitio rápido es un buen extra. Para muchos, supongo que también es el placer de tener una instalación que se entiende por completo.

Lo que queda: WordPress es la opción convencional y segura con el mayor ecosistema; Hugo, un nicho elegido a propósito. Estar en minoría no es un argumento en ningún sentido.

🛡️ ¿Sería SELinux más sencillo?

Sí, claramente en la parte web, aunque no desaparece. El artículo a fondo sobre SELinux muestra cuánto trabajo hay ahí.

TemaWordPress sobre K3sHugo sobre AlmaLinux
Paquete de reglas para contenedoresk3s-selinux, aún no estable para AlmaLinux 10No hace falta
Dominios de la parte webContenedores con sus categoríasnginx en el probado httpd_t
ArchivosVolúmenes y etiquetas de contenedorUna carpeta como httpd_sys_content_t
Reetiquetar tras descargar K3sObligatorioNo aplica
Proxy hacia GrafanaA través del ingress en un podUn booleano o un puerto etiquetado
Mis dominios de monitorización (homelab_*)Se quedanSe quedan
Denegaciones ocultas por dontauditHay que comprobarlasHay que comprobarlas
Esfuerzo de migración—Nueva fase de aprendizaje para nginx en el servidor

En FreeBSD la pregunta cambia por completo, porque allí no existe SELinux. Su lugar lo ocupan las jails y el framework MAC.

Lo que queda: desaparece la parte más difícil de SELinux, los contenedores y su paquete. Se mantiene el modo enforcing, y también la obligación de comprobar el dominio real de cada servicio.

📊 Grafana se queda. ¿Qué implica eso?

Hoy Grafana funciona como un servicio normal del sistema, pero se accede a él a través del ingress de K3s. Esta es la dependencia más importante:

ParteHoyCon HugoEsfuerzo
Servicio GrafanaServicio del sistemaSin cambiosNinguno
Acceso por /grafana/Ingress de K3sProxy inverso en el nginx del servidor, con WebSocketPequeño
Filtro geográfico del accesoEn el ingressPasarlo al nginx del servidorPequeño
fail2ban para el acceso a GrafanaLee registros de podsLee el registro de nginx, nueva ruta y filtroPequeño
PrometheusNode, kubelet, kube-state, MariaDB, PHP-FPMNode y un exportador de nginxPequeño
Alloy y LokiLeen /var/log/podsLeen /var/log/nginx y el journalMedio
Panel de contenedoresDisponibleYa no en este servidorRetirar
Paneles de PHP-FPM, MariaDB, RedisDisponiblesYa no en este servidorRetirar
Alertas de workers, pods, base de datosActivasRetirarlas o notificarán NoDataMedio
Nuevo: peticiones y errores de nginxA través del ingressCon el exportador de nginx y los registrosMedio
Nuevo: último despliegue correcto—Métrica de marca de tiempo con alertaPequeño
Caducidad de certificados TLSComprobación de Monit en el ingressComprobación de Monit en el servidorPequeño
MemoriaAlrededor de 1 GBAlrededor de 1 GBDetermina el tamaño del servidor

Aquí se aplica directamente una lección anterior: si retiro métricas y olvido una regla, puede dejar de avisar y quedarse en verde para siempre. Por eso, tras la migración comprobaría el estado de cada regla y no la ausencia de correos.

Una alternativa sería un Grafana central en casa que recoja datos de todos los servidores. Quitaría el último acceso del servidor del blog, pero es una decisión aparte, con sus propios riesgos.

Lo que queda: conservar Grafana no es un obstáculo. Sí significa que el proxy inverso, el filtro geográfico y un acceso se quedan en el servidor, y que la monitorización debe mirar a nginx en vez de a los pods.

🎭 Los roles de Ansible, uno por uno

Mi primera suposición fue que apenas quedarían roles. Era falsa. La mayoría de los roles protegen el servidor y no WordPress, así que la mayoría se queda. Estos son los 29 roles de blog.yml, con el número de líneas referidas a Kubernetes:

RolLíneasLíneas K8sCon Hugo
blog_k3s_deploy2.96269❌ Eliminado
blog_wordpress1.47345❌ Eliminado
common_k3s1.139186❌ No en este servidor (Nextcloud lo conserva)
common_kube_metrics2145❌ No en este servidor
common_trivy40614❌ No en este servidor (sin imágenes)
blog_packages2220🔄 Reescribir: nginx, cliente ACME, rsync
blog_verify47813🔄 Reescribir: sitio, certificados, enlaces, despliegue
blog_visitor_stats2373🔄 Nueva ruta de registro, misma idea
common_version_check34049🔄 Nueva rama para el blog
common_version_active22317🔄 Nueva rama para el blog
common_fail2ban48742🔧 Rutas nuevas, sin jail de WordPress
common_firewall1.17918🔧 Más simple: sin tablas de K3s ni NodePorts
common_monit70212🔧 Sin control de pods; controles de nginx y despliegue
common_grafana1.5520🔧 Menos paneles y alertas
common_loki8437🔧 Archivos de registro en vez de registros de pods
common_prometheus4511🔧 Otros destinos
common_selinux2206🔧 Sin k3s-selinux; reglas de nginx
common_selinux_monitoring3990🔧 Menos dominios
common_clamav2610🔧 Probablemente apagado: sin subidas en el servidor
common_cis_hardening5718🔧 Quitar excepciones de K3s
common_auditd2524🔧 Quitar rutas de K3s
common_sysctl3132🔧 Quitar ajustes de K3s
common_aide_refresh1011🔧 Carpeta web excluida a propósito
common_dnf_automatic2251🔧 Pequeño ajuste
common_ssh6500✅ Sin cambios
common_msmtp1380✅ Sin cambios
common_rkhunter1870✅ Sin cambios
common_logrotate1150✅ Sin cambios, se añade nginx
common_node_exporter2731✅ Sin cambios
ResultadoRoles
❌ Fuera de este servidor5
🔄 Reescribir5
🔧 Ajustar14
✅ Sin cambios5

En líneas, unas 6.200 de las aproximadamente 16.600 líneas que el blog recorre hoy ya no se usarían allí, es decir, un 37 %. Solo unas 4.400 saldrían realmente del repositorio, porque los Nextcloud necesitan el resto. El recorrido de Ansible sobre el blog se convertiría en un documento histórico.

Por supuesto, habría que crear algunas cosas nuevas:

NuevoQué haceTamaño
Rol para el sitio estáticonginx en el servidor, cabeceras de seguridad, redirecciones, proxy de GrafanaMedio
CertificadosCliente ACME con renovación y recarga de nginx, en lugar de cert-managerPequeño
DespliegueUsuario restringido, rsync, carpeta nueva por versión, cambio atómico, últimas versiones conservadasPequeño a medio
Exportador de nginxPeticiones y errores para PrometheusPequeño
Cadena de construcciónVersión de Hugo fijada, construir, comparar, índice de búsqueda, subirMedio
VerificaciónControl de enlaces y comparación de contenido en cada construcciónYa existe del experimento
Tabla de redireccionesDirecciones antiguas como el feed y las rutas de mediosPequeño
Copia de seguridadSimplificada: contenido en Git, más configuración del servidor y registrosPequeño

Lo que queda: los roles caros desaparecen, la base de seguridad se queda. Es una buena noticia: el endurecimiento construido durante meses se conserva.

📦 ¿Un repositorio nuevo?

Mi repositorio contiene ahora las dos pilas. Los roles comunes deciden por la variable stack, y mi regla es que cada cambio debe funcionar para ambas. Pasar a Hugo plantea cómo dividirlo:

OpciónVentajaInconveniente
A: todo en el repositorio actualUn lugar, un historialCada artículo e imagen entra en el historial de Ansible y pasa por su lint; el repositorio crece con los medios
B: repositorio nuevo para contenido, tema y construcción. Ansible se quedaSeparación limpia; sin cambios en los roles comunes; CI propia y simpleDos repositorios; el despliegue debe conectarlos
C: separación completa con roles comunes como colecciónLimpio para varios usuariosVersiones y publicaciones para solo dos usuarios; esfuerzo alto
D: repositorio de Ansible aparte para el blog con roles copiadosTotalmente independienteCada corrección de seguridad, por duplicado; las copias divergen

Yo elegiría la opción B. Artículos, imágenes, tema y scripts de construcción irían a un repositorio nuevo. El servidor sigue en el repositorio de Ansible con un tercer valor, stack: static. Los roles siguen en un solo lugar y el endurecimiento no hay que mantenerlo dos veces. Para publicar basta una clave de despliegue restringida, sin acceso al código de Ansible ni a su vault.

El precio es real, eso sí: la regla «funciona para ambas pilas» pasaría a ser «funciona para las tres». A cambio, las ramas de WordPress desaparecen de muchos roles.

Lo que queda: contenido e infraestructura cambian a ritmos distintos y guardan secretos distintos, así que deben estar en repositorios separados. El endurecimiento común no debe copiarse.

🐡 ¿Y en FreeBSD?

Llevo años entusiasmado con FreeBSD, aunque junto a Linux lleve una existencia de nicho. Es un sistema completo y coherente, con muy buena documentación, jails, ZFS y pf. Aun así, para este blog nunca tuvo opción, porque K3s depende de funciones del núcleo Linux y allí no funciona de forma apta para producción.

Eso es exactamente lo que cambia Hugo. Sin K3s, contenedores, PHP ni base de datos, los requisitos se reducen a nginx, un cliente ACME, rsync y la monitorización, y todo eso es software corriente en FreeBSD. La complejidad que me ataba a Linux ha desaparecido. Esta es la comparación de las tres variantes:

TemaWordPress sobre K3sHugo sobre AlmaLinuxHugo sobre FreeBSD
RAM con monitorización completa (estimación)2,7 GBUnos 1,0–1,2 GBUnos 1,0–1,2 GB
Parches➖ Muchas capas➕ Sistema y nginx➕ freebsd-update y pkg
Actualizaciones automáticas➕ Existen➕ Existen➖ Hay que construirlas
Aislamiento de servicios➕ SELinux y pods➕ SELinux y sandbox de systemd➖ Jails, más toscas pero simples
Cortafuegos y bloqueos➕ Existen➕ Existen, más simples➖ pf y fail2ban nuevos
Roles reutilizablesTodos24 de 29, en parte ajustadosPocos; casi todo sería nuevo
Grafana, Prometheus, Loki➕ Existen➕ Existen, ajustados➖ Hay paquetes; rutas y reglas nuevas
Instantáneas antes de actualizar➖ Ninguna➖ Ninguna por defecto➕ ZFS
Operación junto a los Nextcloud➕ Igual➕ Mismo sistema➖ Segunda plataforma
Conocimiento existente➕ Grande➕ Grande➖ Hay que adquirirlo
Valor como tema del blogYa escritoMedio➕ Alto

La pregunta decisiva es si esta instalación podría protegerse tan bien como la actual. La he valorado capa por capa. Es una valoración sobre el papel: no la he construido ni probado en FreeBSD.

CapaHoy en AlmaLinuxHugo sobre FreeBSDValoración
Filtro de paquetesnftablespf con tablas🟢 Equivalente
Endurecimiento de SSH, filtro geográficosshd y conjuntos de nftablessshd y tablas de pf🟢 Equivalente
Bloquear atacantesfail2banfail2ban con pf🟢 Equivalente, con reglas nuevas
Aislar nginxSELinux y sandbox de systemdJail, contenido montado solo lectura🟢 Bueno; simple y fácil de comprobar
Aislar la monitorizaciónMis dominios de SELinuxUna jail por servicio🟡 Más tosco, pero con fronteras claras
Reglas finas por procesoType enforcement de SELinuxSin equivalente directo; framework MAC, Capsicum solo si el software lo admite🔴 Más débil
Superficie de ataque del servidor webCon WordPress: grandeArchivos estáticos🟢 Mucho menor que hoy
Información sobre vulnerabilidadesdnf, Trivypkg audit y freebsd-update🟢 Buena
Registro de auditoríaauditdOpenBSM🟡 Equivalente en principio; hay que rehacer el análisis
Integridad de archivos, rootkitsAIDE, rkhunterAIDE, rkhunter, freebsd-update IDS🟢 Equivalente
Marcha atrás tras una actualizaciónPaquetes, restauraciónInstantáneas de ZFS y boot environments🟢 Mejor
Base de endurecimientoReferencia CIS aplicada en mi rolHay que rehacerla a mano🟡 Esfuerzo; menos material preparado
GrafanaTras filtro geográfico y fail2banIgual, en su propia jail🟡 Sigue siendo el mayor objetivo
Experiencia con incidentes realesMeses de hallazgos realesEmpieza de cero🔴 Más débil al principio

Mi valoración: sí, para un sitio estático, FreeBSD podría protegerse a un nivel global parecido, aunque con otros medios. Lo que perdería de verdad es el control fino de SELinux por proceso. Con un WordPress con PHP y plugins, eso dolería. Con un nginx que entrega archivos en solo lectura desde una jail, pesa mucho menos, porque un atacante puede hacer sencillamente mucho menos. A cambio, las jails son lo bastante simples para comprobarlas a simple vista. Los dos puntos débiles reales son Grafana, que sigue necesitando un acceso, y mi falta de práctica: mi instalación de AlmaLinux ha pasado por meses de errores reales, y una de FreeBSD no.

Un punto abierto: que yo sepa, los paquetes de Grafana, Prometheus, Loki y node_exporter están en los ports de FreeBSD, pero antes tendría que comprobar Alloy y las versiones actuales. De lo contrario, haría falta otro recolector de registros.

Lo que queda: la gran ganancia viene de Hugo, no del sistema operativo. Pero es Hugo lo que hace posible FreeBSD: sin K3s, la elección ya no es técnica. Sería una elección por convicción y, para un sitio estático, una elección defendible.

💶 Costes y beneficios

PuntoCosteBeneficio
MigraciónÚnico, véase abajo—
Servidor—Posible servidor más pequeño y barato
MantenimientoNueva cadena de construcción que mantenerMuchos menos parches y alertas
SeguridadProteger la clave de despliegue y la construcciónVarias clases de ataque eliminadas
Velocidad—Menos que descargar; mejor en picos y fuera de caché
EscrituraSin editor ni trabajo desde el móvilHistorial de Git, archivos simples, fácil con IA
Copias de seguridad—Mucho más simples
Portabilidad—Markdown funciona en todas partes; sin atadura a una base de datos
ConocimientoSe pierde el banco de pruebas de K3sMenos casos especiales en la cabeza
SEORiesgo durante el traslado; sin análisis de YoastPáginas rápidas y control total
Material para el blogMenos historias de operación en este servidorUna buena historia de migración

No puedo dar aquí un precio de servidor útil, porque depende del proveedor. De todos modos, el ahorro es modesto. La verdadera moneda aquí es la atención.

Lo que queda: esta migración no se paga con dinero ni devuelve dinero. Es un intercambio: comodidad al escribir a cambio de mucho menos trabajo de operación.

⏱️ ¿Cuánto trabajo sería?

El blog tiene 143 artículos en cada uno de los cuatro idiomas, 572 en total, además de 16 páginas estáticas y alrededor de 1.400 archivos de medios. Los valores siguientes son estimaciones. El experimento llevó aproximadamente una tarde con ayuda de la IA, lo que sugiere que la conversión es la parte más pequeña.

FaseCon ayuda de la IANota
Inventario: plugins, bloques especiales, descargas2–3 hLa herramienta de exportación existe
Convertir todos los artículos y medios3–6 hEl script existe; los artículos antiguos guardan sorpresas
Terminar el tema: paginación, etiquetas, archivos, móvil3–5 hLa base existe
SEO: direcciones, redirecciones, feed, schema, sitemap2–3 hComparación automática con el sitemap actual
Ansible: rol nuevo, 14 ajustados, 5 reescritos, VM de pruebas8–15 hLa parte mayor
Monitorización y Grafana3–5 hComprobar cada regla
Copia, prueba de restauración, documentación en tres idiomas, texto de privacidad3–5 hDebe hacerse con cuidado
Cambio y vigilancia activa2–3 hDespués, dos semanas de observación
Total, Hugo sobre AlmaLinuxUnas 26–45 hEn la práctica, repartidas en 2–3 semanas
Adicional para FreeBSDUnas 15–30 hPocos roles reutilizables
Sin ayuda de la IA (estimación aproximada)3–5 semanas de trabajoSobre todo tema, conversión y tres idiomas

Las ejecuciones reales en producción, la revisión de cada diff y las decisiones siguen siendo mías. La IA acelera la escritura, pero no elimina la obligación de comprobar.

Lo que queda: la mayor parte del trabajo no está en la conversión, sino en Ansible, la monitorización y la verificación. Ahí es donde hay que reservar tiempo.

✅ Lo que tendría que hacer si elijo Hugo

  1. Aclarar el requisito: ¿puedo vivir sin editor en el navegador ni trabajo desde el móvil? Sin esta respuesta, todo lo demás da igual.
  2. Elegir la plataforma: AlmaLinux por defecto, FreeBSD solo como decisión consciente.
  3. Hacer una copia completa: base de datos, archivos y medios. Mantener WordPress disponible varias semanas.
  4. Crear el repositorio de contenido con artículos, medios, tema y versión fijada de Hugo. Buscar secretos antes del primer push.
  5. Convertir todo y comparar automáticamente cada página: texto, bloques de código con sus barras invertidas, tablas, enlaces, textos alternativos, títulos y descripciones.
  6. Conservar cada dirección: artículos, idiomas, categorías, etiquetas y también /wp-content/uploads/, porque hay imágenes enlazadas desde fuera. Comparar con el sitemap actual.
  7. Configurar redirecciones: sin configuración, el feed RSS pasa de /feed/ a /index.xml. Comprobar también los enlaces ?p= y la antigua dirección de búsqueda.
  8. Reescribir la política de privacidad y revisar el aviso legal. El texto actual describe WordPress y sus plugins. Revisar también el aviso de IA y las licencias de todas las descargas.
  9. Terminar el tema y el SEO, incluidas imágenes Open Graph por debajo del límite de WhatsApp y noindex para las páginas legales.
  10. Construir la parte de Ansible en una VM de pruebas: stack: static, el rol nuevo, los roles ajustados. Ejecutarlo dos veces; la segunda debe mostrar changed=0.
  11. Comprobar SELinux de verdad: dominios con ps -eZ, denegaciones ocultas con semodule -DB y el registro propio de cada servicio.
  12. Rehacer la monitorización: Grafana tras nginx con filtro geográfico y fail2ban, exportador nuevo, reglas antiguas retiradas y, después, comprobar el estado de cada regla.
  13. Proteger la vía de despliegue: clave restringida, cambio atómico, últimas versiones conservadas y una alerta si falla el despliegue.
  14. Probar una restauración: construir un servidor limpio solo desde los repositorios, antes de tocar producción.
  15. Adaptar todo lo demás: scripts de copia, vigilancia externa, control de actualizaciones y de deriva, guías de operación en tres idiomas y una nota en los artículos a fondo antiguos.
  16. Planificar el cambio: bajar el TTL del DNS, elegir un momento tranquilo, tener lista la marcha atrás y luego revisar buscadores y errores 404 en los registros.
  17. Observar durante dos semanas, y solo entonces retirar WordPress y K3s del servidor.

Lo que queda: la mayoría de estos puntos no tienen nada que ver con Hugo. Tratan de no perder direcciones, cumplir la ley, mantener la monitorización y conservar una vía de retorno.

🌐 ¿Sería HTTP/3 más sencillo?

En parte. Como conté en el artículo sobre HTTP/3, lo desactivé porque las conexiones se colgaban tras una recarga. Con nginx directamente en el servidor, la configuración sería más sencilla, ya que desaparece el rodeo por el ingress. La causa, sin embargo, sigue ahí: los workers antiguos retienen los sockets UDP. Es un asunto de nginx y no de K3s, y por eso abrí la issue #1937. Menos conexiones largas y recargas poco frecuentes suavizarían el problema. No lo he probado. En un sitio estático el beneficio sería pequeño de todos modos, así que por ahora lo dejaría desactivado.

Lo que queda: una configuración más sencilla no corrige un fallo de la capa inferior.

🎯 Las lecciones

  1. Medir antes de creer. Esperaba una gran ganancia de velocidad. Un WordPress en caché respondió en 58 ms, un archivo estático en 57 ms.
  2. La mayor parte del beneficio está en la operación. El software que ya no existe no necesita parches, alertas ni urgencias.
  3. El endurecimiento sobrevive. Mi suposición de que quedarían pocos roles era falsa: 24 de 29 se quedan al menos en parte, porque protegen el servidor.
  4. «Estático» no significa automáticamente «simple». Grafana, el despliegue y la cadena de construcción se quedan, y el riesgo pasa a la clave de despliegue.
  5. Una migración necesita una herramienta de comparación. Sin ella, no habría visto los enlaces de teléfono rotos en mi aviso legal.

🤔 Dónde estoy ahora

No he decidido. Para este blog, K3s y WordPress ya no son técnicamente necesarios, eso está claro. Igual de claro es que me cuestan atención, no experiencia de lectura. Al otro lado están el editor, el banco de pruebas de K3s para los Nextcloud y una instalación que funciona y que conozco muy bien.

Si me decido, será con Hugo y un repositorio de contenido separado, y la monitorización se queda. AlmaLinux es la opción sensata, porque casi todo se conserva. FreeBSD es la opción que me entusiasma y, por primera vez, sería realista en este blog. Y si lo hago, habrá una segunda parte con las cifras reales, incluido todo lo que estas estimaciones hayan fallado.

Parte de los textos e imágenes de este sitio está asistida o generada por IA. Detalles