Varias recetas básicas con Varnish Cache

En este artículo publico varias recetas muy básicas con Varnish: arranque de Varnish, redirección de un dominio a un origen con otro nombre, redirección en función de una expresión regular y el contenido de una cookie, y una terminación SSL utilizando Nginx como front-end. Reconozco que la información del post está un poco apretada. Estos temas merecen expandirse y profundizar más. Lo haré en sucesivos posts. Escribo, en parte, este post rápido por si más adelante me es útil a mí.
En Debian Jessie ya no se utiliza la variable DAEMON_OPTS, por lo que definirla no tendrá efecto. En su lugar, hay que configurar el archivo /etc/system.d/system/varnish.service con las opciones de arranque.
Para arrancar con el puerto 80 a la escucha y 1024 megabytes de RAM, hay dejar la variable ExecStart así:
ExecStart=/usr/sbin/varnishd -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,1024m
Para recargar la configuración:
systemctl restart varnish
Comprobamos que Varnish esté a la escucha por el puerto 80
ps aux | grep varnish root 884 0.0 1.4 126872 86084 ? SLs 09:51 0:00 /usr/sbin/varnishd -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,1024m nobody 887 0.2 1.4 320916 86672 ? Sl 09:51 0:02 /usr/sbin/varnishd -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,1024m root 2149 0.0 0.0 12772 2200 pts/1 S+ 10:04 0:00 grep varnish
Redirigir de un dominio a otro origen
Para redirigir una petición de un dominio a otro, suponiendo el siguiente escenario:
- Un servidor web a la escucha en el puerto 8080 con una página generada por la funcion phpinfo(). El sitio tiene el imaginativo nombre de sitio.local.
- Un cliente que hace peticiones a foo.sitio.local.
- Varnish se encargára de redigir del dominio que pide el cliente al origien del servidor web.
En el archivo /etc/varnish/default.vcl definimos el backend:
backend sitio { .host = "192.168.122.173"; .port = "8080"; }
En el bloque vcl_recv:
sub vcl_recv { set req.http.x-host = req.http.host; set req.http.x-url = req.url; if (req.method != "GET" && req.method != "HEAD") { return (pass); } if (req.http.Host=="foo.sitio.local") { set req.http.Host = "sito.local"; set req.url = "/info.php"; set req.backend_hint = sitio; return(hash); } }
En el bloque vcl_backend_response:
sub vcl_backend_response { set beresp.http.host = beresp.http.x-host; }
Esto cambiará el nombre de host en el encabezado de respuesta que recibirá el cliente, para que le llegue la información del mismo nombre del host de la petición que hizo el cliente.
Cambiando origen en función del contenido de una cookie
En el mismo servidor web, editamos un archivo llamado info.php e introducimos el siguiente contenido:
<?php $cookie_name = "galletita"; $cookie_value = "azucar"; echo "Name: " . $cookie_name . "<br />"; echo "Value: " . $cookie_value; setcookie($cookie_name, $cookie_value, time() + (86400 * 30)); if(count($_COOKIE) > 0) { echo "Cookies are enabled."; } else { echo "Cookies are disabled."; } ?>
Con esto creamos una cookie llamada «galletita» con el valor «azucar».
Definimos un nuevo backend, al que será redirigida la petición en función del contenido de una cookie.
backend pagina { .host = "192.168.122.173"; .port = "8080"; }
En el bloque vcl_recv escribimos una condición para que reenvíe a la siguiente acción del cache con un return(pass):
if (req.http.Host == "foo.sitio.local" && req.http.Cookie ~ "galletita=azucar") { set req.http.host = "pagina.local"; set req.backend_hint = pagina; }
Esta condición cambia el origen a pagina.local cuando el req.http.host del encabezado sea foo.sitio.local y una cookie llamada «galletita» contega el valor «azucar».
Cambiar origen en función de una expresión regular
El infinito tema de las expresiones regulares. Sólo a modo de ejemplo, usaré una expresión regular simple. Las expresiones regulares están muy bien documentadas en Internet y no es difícil encontrar buenos tutoriales y manuales, como éste y con mayor profundidad éste otro.
if (req.http.Host == "foo.sitio.local" && req.url ~ "^/blog(\W|$)") { set req.http.host = "blog.local"; set req.url = "/index.php"; set req.backend_hint = blog; return(hash); }
Manual introductorio de Varnish Cache
Cuando una url sea «/blog» sin ningún otro carácter, dirigirá las peticiones del cliente al origen blog.local. El backend previamente habrá sido definido del siguiente modo:
backend blog{ .host = "192.168.122.173"; .port = "8000"; }
Limitando acceso al PURGE del caché
El primer paso es crear una ACL con los hosts o direcciones IP permitidas para lanzar la acción cache. Para limitar el acceso a una sóla IP:
acl purge { "192.168.122.10"; }
Esta variable la usamos en vcl_recv:
if (req.method == "PURGE"){ if (!client.ip ~ purge) { return(synth(405,"Forbidden - Not allowed")); } return(purge); }
Tan solo si la IP coincide con alguna de las IP’s de variable purge, pasa a la acción purge.
Añadimos a la subrutina vcl_purge:
sub vcl_purge { if (req.method != "PURGE") { set req.http.X-Purge = "Yes"; return(restart); } return (synth(200,"Purged")); }
Para borrar una caché de manera remota:
curl -X PURGE pagina.local Salida: <!DOCTYPE html> <html> <head> <title>200 Purged</title> </head> <body> <h1>Error 200 Purged</h1> <p>Purged</p> <h3>Guru Meditation:</h3> <p>XID: 32811</p> <hr> <p>Varnish cache server</p> </body> </html>
Terminación Nginx-SSL con backend Apache
Para redirigir las peticiones https al puerto 80 de Varnish y que éste conecte al backend Apache, por ejemplo a pagina.local en el puerto 8000, es posible utilizar Nginx como front-end para dirigir las peticiones a Varnish
CLIENTE —> NGINX:443 —> VARNISH:80 —> APACHE:8000
La configuración del front-end en Nginx:
server { server_name pagina.local; listen 443 ssl; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { proxy_pass //127.0.0.1:80; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Host $host; proxy_set_header HTTPS "on"; } }
Aquí escuchamos en el puerto 443 y utilizamos los certificados. La línea proxy_pass redirige el tráfico desde el puerto 443 al puerto 80 del host local.
En el bloque vcl_recv añadimos:
if ( (req.http.host ~ "^(?i)pagina.local") && req.http.X-Forwarded-Proto !~ "(?i)https") { set req.http.x-Redir-Url = "//" + req.http.host + req.http.url; return(synth(750, "")); }
En vcl_synth:
sub vcl_synth { if (resp.status == 750) { set resp.http.Location = req.http.x-redir; set resp.status = 301; return (deliver); } }
En próximos posts, más y mejor sobre Varnish.