En este tutorial explicaremos como configurar Varnish Cache junto con Ghost CMS para acelerar la carga de nuestra web.

Si tenemos Ghost instalado en nuestro servidor con Nginx como Proxy, cada vez que Nginx reciba una petición, ésta debe de pasar directamente a Ghost, que deberá de cargar el contenido necesario desde el disco. Aun que el disco de nuestro servidor pueda ser un SSD, el proceso puede ser lento.

Pero aquí hemos venido a mejorar el rendimiento de nuestra web. Así que lo que haremos será añadir una capa entre Nginx y Ghost para que Varnish almacene en caché el contenido estático en la RAM y que sólo pase las peticiones de contenido que no se almacenen en cache.

Así que vamos al lío. Este tutorial ha sido realizado utilizando un servidor Ubuntu 22.04 con la instalación de Ghost en local y utilizando un Nginx Proxy. Aquí te dejamos el procedimiento de su instalación.

Instalar Ghost CMS con Ghost-CLI
Ghost es una plataforma de blogging desarrollada sobre NodeJS y Handlebars (y con sqlLite3 por defecto) que es totalmente de Código Abierto con una idea muy clara: hacer una cosa y hacerlo muy bien. De esta manera se centran exclusivamente a la creación de contenido y nada más (por eso

Primero entendamos la nueva estructura

Lo que tenemos ahora es un Nginx Proxy escuchando al puerto 2368 directamente en localhost, que es donde Ghost está escuchando. De esta manera, cuando se hace una petición al puerto 80/443 responde Nginx que directamente pregunta a Ghost para responder con el contenido que se pide.

Para que tengamos algo visual, sería algo así:

Pero lo que nosotros queremos, es meter a Varnish Cache en medio de todo este proceso, para que en vez de que Ghost responda las mismas peticiones una y otra vez, sea Varnish que diga "Epa, que tengo ya este contenido, toma que yo voy más rápido".

Para esto, tenemos que pasar del esquema anterior a este otro:

Cuando tengamos esto, lo que sucederá es que cuando Nginx tenga la petición preguntará directamente a Varnish. Si Varnish tiene la petición cacheada, entonces responderá él. En caso contrario, Varnish preguntará directamente a Ghost y cacheará esa petición para futuras ocasiones.

Instalación de Varnish Cache

Lo primero es instalar Varnish Cache en nuestro servidor, para ello solo tendremos que ejecutar lo siguiente:

# apt-get install varnish
💡
Varnish almacena el contenido en caché en la memoria del sistema (RAM). Por defecto, se asignan 256MB de RAM para la caché. Si tienes un servidor con RAM limitada, puede que necesites ajustar este valor para evitar que Varnish cause problemas en el sistema. Para ello es necesario editar el fichero /lib/systemd/system/varnish.service y modificar -s malloc,256m por otro valor que se adapte a tu configuración.

Apuntamos Ghost hacia Varnish

Por defecto, Varnish está escuchando al puerto 8080, pero Ghost está escuchando al puerto 2368, por lo que deberemos de modificarlo en la configuración de Varnish.

 # nano /etc/varnish/default.vcl

Modificaremos el backend default y cambiaremos el puerto 8080 por el 2368:

backend default {
    .host = "127.0.0.1";
    .port = "2368";
}

Apuntamos Nginx a Varnish

El siguiente paso será hacer que Nginx Proxy escuche por el puerto que tiene configurado Varnish. Para ello tendremos que editar la configuración de Nginx y cambiar lo siguiente:

proxy_pass http://127.0.0.1:2368;

Por esto:

proxy_pass http://127.0.0.1:6081;

En este punto, ya tenemos Nginx escuchando por el puerto 6081, que es el puerto que tiene Varnish y que responde a las peticiones escuchando por el puerto 2368 que es donde está escuchando Ghost.

Reiniciamos los servicios

Una vez tenemos toda la configuración correctamente, es el momento de reiniciar los servicios. Primero de todo, activaremos Varnish y lo habilitaremos en el arranque:

systemctl start varnish
systemctl enable varnish

También comprobamos la configuración de Nginx y recargamos la configuración:

nginx -t
systemctl reload nginx

Y si todo ha ido bien, deberemos de acceder de nuevo a nuestro blog pero esta vez responderá Varnish y lo podremos comprobar con curl:

$ curl -I https://tutos.top
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Wed, 13 Sep 2023 19:06:44 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 11010
Connection: keep-alive
X-Powered-By: Express
Cache-Control: public, max-age=0
ETag: W/"2b02-SZbgQNmoFaMNMxwU0Bi9fwOCs8s"
Vary: Accept-Encoding
X-Varnish: 65591
Age: 0
Via: 1.1 varnish (Varnish/6.6)
Accept-Ranges: bytes

Si observamos la respuesta, vemos que la petición ha sido aceptada vía 1.1 varnish (Varnish/6.6).

Configuración de Varnish

Ahora que ya tenemos Varnish funcionando correctamente en nuestro servidor, podemos empezar a modificar la configuración para decirle a Varnish qué queremos que guarde en la caché, y por lo tanto, que ignorar de la caché.

Dependiendo de lo que tengamos con Ghost, lo que almacenemos en caché puede variar. Por ejemplo, si tenemos activado la opción de miembros en Ghost, no nos interesará almacenar en caché la información de un usuario para que luego se sirva a otro usuario. Por defecto, las peticiones con cookies no se almacenan en caché.

Así que nos tocará volver al fichero de configuración de Varnish y revisar las diferentes secciones que tiene.

La primera sección que vemos se llamaba sub vcl_recv, en esta sección se añadirá lo que queremos que ocurra antes de comprobar si ya lo tenemos en caché.

Luego tendremos otra sección llamada vcl_backend_respose donde tendremos lo que ocurre después de que hayamos leído las cabeceras de respuesta del backend.

Finalmente, tenemos la tercera sección llamada sub vcl_deliver donde pondremos lo que sucede cuando tenemos todas las piezas que necesitamos y estamos a punto de enviar la respuesta al cliente.

vcl_recv

En el caso de que no tengas la parte de miembros activada, entonces puedes añadir esta configuración dentro de esta sección:

sub vcl_recv {
  if (req.url ~ "/ghost") { 
    return (pass);
  } else {
    return (hash);
  }
}

De esta forma prevenimos que /ghost sea cacheada. Pero si por lo contrario tienes la parte de miembros activada, entonces deberás de añadir esto otro:

sub vcl_recv {
  if (req.url ~ "/assets" || req.url ~ "/content/images") {
    return (hash);
  } else {
    return (pass);
  }
}

vcl_backend_reponse

Ahora que hemos dirigido las peticiones a la ubicación deseada, podemos modificar las cabeceras de respuesta. Por ejemplo, podemos modificar la edad máxima de la caché.

sub vcl_backend_response {
  if (bereq.url ~ "/assets" || bereq.url ~ "/content/images") {
    set beresp.http.cache-control = "public, max-age=259200";
    set beresp.ttl = 3d;
    return (deliver);
  }
}

Con esto estamos diciendo que el tiempo máximo de vida sea de 259200 y si hacemos peticiones a una imagen podremos observar lo siguiente:

curl -v https://tutos.top/content/images/2023/09/image.png 2>&1 | grep "age:"
< age: 24

A medida que vayamos haciendo ejecutando el mismo comando, el valor de age irá creciendo. Pero si reiniciamos Varnish, lo que significa, limpiar cache, veremos que este valor se pone de nuevo a 0.

systemctl restart varnish

curl -v https://tutos.top/content/images/2023/09/image.png 2>&1 | grep "age:"
< age: 0

Tiempos de carga

Vamos a ver diferentes tiempos de carga con y sin Varnish. Al ser un Ghost sin artículos y con el tema por defecto, no se acaba de notar mucho, pero si que es suficiente como para ver que la petición responde Varnish directamente.

Resultados sin Varnish:

Resultado con Varnish:

Conclusión

Tras configurar la cache de Varnish, el siguiente paso sería configurar un webhook con Ghost para limpiar la cache automáticamente, os dejo el artículo a continuación:

Crear un webhook en Ghost para limpiar la caché de Varnish
Recientemente hemos hablado sobre como configurar Ghost con Varnish para acelerar la carga de contenido.

Haz que cada palabra cuente: tu donación nos inspira a seguir creando contenido. Accede al apartado de Donación para hacer tu aportación