El problema real: Drupal no escala solo
Drupal es robusto. Eso nadie lo discute. Pero cuando metes tráfico de verdad, su arquitectura PHP + MySQL te pasa factura petición a petición. Cada página que sirve arranca el bootstrap, dispara hooks de decenas de módulos, recorre el render pipeline y consulta la base de datos varias veces. En un sitio con contenido medianamente complejo, eso son entre 200 y 800 ms por petición sin caché. Multiplica por miles de visitantes simultáneos y ya tienes el cuello de botella.
El Page Cache y el Dynamic Page Cache internos de Drupal hacen su trabajo. Para un blog corporativo con tráfico tranquilo, sobran. ¿Pero qué pasa cuando lanzas una campaña y te llegan diez mil usuarios en cinco minutos? ¿O cuando tu objetivo de TTFB es de 50 ms y no puedes negociarlo? Ahí la caché interna se queda corta. Necesitas algo delante. Necesitas Varnish.
Varnish se sienta entre el visitante y tu servidor web, sirve respuestas directamente desde RAM y deja a PHP completamente fuera del camino caliente. Hablamos de tiempos de respuesta de 1 a 10 ms en cache hit. Y el módulo Purge de Drupal cierra el bucle: cuando un editor publica o modifica algo, Purge le dice a Varnish qué tirar de la caché. Sin esa pieza, acabarías sirviendo contenido caducado.
Cómo encaja todo: la arquitectura
El flujo es sencillo cuando lo dibujas:
- El visitante pide una URL.
- Varnish recibe la petición en el puerto 80 (o detrás de un terminador TLS si usas HTTPS, que deberías).
- Mira en su almacén en memoria. ¿La tiene? La devuelve en milisegundos. ¿No la tiene? La pide al backend, la guarda, y la sirve.
- Cuando un editor toca contenido en Drupal, Purge encola una invalidación y se la lanza a Varnish vía HTTP.
- La próxima visita a esa URL vuelve a ser miss, Varnish refresca desde Drupal, y todo sigue.
Las piezas que necesitas
- Varnish Cache: el proxy en sí. Para proyectos nuevos, ve directo a la rama 7.x.
- Módulo Purge: el framework de invalidación. Gestiona la cola, los procesadores y los purgadores.
- Módulo Varnish Purger: el purgador concreto que habla con Varnish vía PURGE o BAN.
- Módulo Cache Tags Header: hace que Drupal exponga sus cache tags como cabeceras HTTP. Sin esto, no hay invalidación granular.
- VCL (Varnish Configuration Language): el archivo donde defines qué cachear, durante cuánto, cómo tratar cookies y cómo aceptar las purgas. Aquí es donde se gana o se pierde el partido.
Instalar Varnish y dejarlo listo
En Debian o Ubuntu, apt install varnish y listo. La parte interesante viene después, en la configuración del servicio y del VCL.
Dos parámetros que no puedes dejar por defecto:
- Puerto de escucha: si tienes Nginx haciendo de terminador TLS, Varnish escuchará en un puerto interno (por ejemplo 6081) y Nginx le pasará el tráfico. Si Varnish está expuesto directamente, ponlo en el 80.
- Backend: la IP y puerto de tu Apache o Nginx aplicacional. Suele ser 127.0.0.1:8080 en stacks de un solo nodo.
El VCL para Drupal, sin atajos
Aquí es donde la mayoría de implementaciones fallan. Vamos por partes.
Cookies: el asesino silencioso del hit rate
Por defecto, Varnish no cachea respuestas con cookies. Y Drupal mete cookies por todas partes: Google Analytics, banners de consentimiento, A/B testing, herramientas de marketing. Si no las limpias antes de decidir el cacheo, tu hit rate va a estar bajo el 20 %.
La regla práctica: en vcl_recv, elimina toda cookie que no empiece por SESS o SSESS (las de sesión autenticada de Drupal). Si tras la limpieza no queda ninguna cookie, cachea. Si queda la de sesión, asume usuario logueado y manda directo al backend sin pasar por caché.
Autenticados vs anónimos
Las páginas de un usuario logueado llevan su nombre, sus permisos, su menú de administración. Cachearlas globalmente es un agujero de seguridad de manual. El VCL detecta la cookie SESS* y hace return(pass) directamente. Punto.
BAN por cache tags
Drupal etiqueta cada respuesta con tags tipo node:42, taxonomy_term:7, config:system.site. Cuando guardas un nodo, Drupal invalida todo lo que lleve ese tag. Para que Varnish entienda el mensaje, configuras un handler de BAN en vcl_recv que acepte una cabecera Purge-Cache-Tags y aplique el ban sobre obj.http.Cache-Tags.
Importante: restringe las IPs autorizadas para hacer BAN. Una ACL con solo los servidores de aplicación. Si dejas el endpoint abierto, cualquiera puede vaciarte la caché desde fuera. Lo he visto pasar más de una vez.
Estáticos
CSS, JS, imágenes, fuentes: TTL alto, sin contemplaciones. Drupal versiona los assets con un query string que cambia cuando el archivo cambia, así que invalidar manualmente no hace falta. Una semana de TTL es perfectamente razonable.
Grace mode: el seguro de vida
Si tu backend cae a las 4 de la mañana, ¿prefieres que tus visitantes vean un 503 o una versión ligeramente desactualizada? Con grace, Varnish sigue sirviendo la copia antigua durante el tiempo que le digas (yo suelo poner 6 horas) mientras el backend se recupera. Cuesta tres líneas de VCL y te salva noches enteras.
Configurar Purge dentro de Drupal
Módulos
composer require drupal/purge drupal/varnish_purger drupal/purge_queuer_url drupal/cache_tags_header y los activas. Toda la configuración vive en /admin/config/development/performance/purge.
El purgador
Añades un purgador "Varnish Purger" y rellenas:
- Hostname: la IP o nombre del servidor Varnish.
- Método HTTP: BAN si trabajas con cache tags, PURGE si invalidas por URL. Mi recomendación es BAN, casi siempre.
- Cabeceras: aquí especificas
Purge-Cache-Tags(o el nombre que hayas puesto en el VCL) como la cabecera que transporta los tags a invalidar.
La cola
Purge no manda invalidaciones a pelo. Las encola y un procesador las despacha. Tienes dos opciones principales:
- Cron processor: procesa la cola cuando corre el cron. Va bien si toleras unos minutos de retraso en la propagación.
- Late runtime processor: vacía la cola al final de cada request. Invalidación casi inmediata, pero añade latencia a las peticiones que hacen el flush.
Para sitios editoriales con cambios constantes, Late runtime. Para sitios con publicaciones esporádicas, Cron sobra.
Verificación end-to-end
Tres pasos para saber si tu configuración respira:
- Carga una página en modo incógnito. Inspecciona cabeceras. Tienen que aparecer
X-VarnishyAge. SiAgecrece entre recargas, hay hit. - Edita el nodo desde Drupal y guarda.
- Recarga.
Agevuelve a 0 y el contenido sale actualizado. Si no, el purger no está enviando, o el VCL no está procesando el BAN.
Optimizaciones que separan lo bueno de lo excelente
ESI para fragmentos vivos
Tu home tiene un bloque de últimas noticias que cambia cada hora. Si invalidas la home entera con cada noticia, pierdes la caché. La alternativa elegante es ESI: cacheas la home con TTL de un día y marcas el bloque de noticias como un fragmento ESI con TTL de cinco minutos. Varnish ensambla las dos cosas en cada respuesta. Drupal tiene módulos contribuidos para esto y Varnish lo soporta nativamente.
Cache warming
Tras un deploy o un drush cr agresivo, la caché está vacía. Las primeras peticiones de cada URL serán lentas. Un script que pasee por tu sitemap y precargue las URLs más visitadas evita que tus usuarios paguen ese coste.
Métricas que importan
varnishstat, varnishlog, o un exporter de Prometheus si ya tienes Grafana montado. Lo que tienes que vigilar:
- Hit rate: por debajo del 90 % en un sitio anónimo es señal de que algo va mal en el VCL.
- Conexiones al backend: un pico raro suele significar que estás invalidando demasiado.
- Evictions: si Varnish está expulsando entradas, te falta RAM. Subir el
-s mallocy listo.
Los errores que veo una y otra vez
- No tocar las cookies: el hit rate se desploma y nadie entiende por qué.
- Invalidar la caché entera con cada guardado: típico de configuraciones que ignoran los cache tags. Si purgas todo, no tienes caché.
- Endpoint de purge sin ACL: invitación abierta a que te vacíen la caché desde Internet.
- Sin grace: el día que el backend falle, vas a recordar este punto.
- RAM insuficiente: Varnish vive en memoria. Si tu working set son 8 GB y le das 2, no hay milagro posible.
Lo que ganas cuando esto funciona
Tiempos de respuesta de milisegundos. Picos de tráfico absorbidos sin sudar. Core Web Vitals que mejoran solos. Servidores más pequeños haciendo el mismo trabajo. Y, sobre todo, una capa de resiliencia que sigue sirviendo aunque el backend tenga un mal día.
Implementar un sistema de caché avanzado con Varnish y Purge en Drupal no es magia, pero sí requiere conocer el VCL, los cache tags y las particularidades de cada sitio. Si quieres saltarte la curva de aprendizaje y dejarlo bien hecho a la primera, hablemos de tu proyecto Drupal.