Varnish + nginx, combinación perfecta

La finalidad de este howto es la dotar a nuestros sites de un sistema de caches para ahorrar ancho de banda en origen, aumentar el rendimiento de los sites y protegernos de posibles fallas en los servidores origen, para ello vamos a utilizar varnish para todo el tema de cacheo de estaticos y nginx para gestionar el tema de multisite de una manera más sencilla y eficiente de la que podriamos hacerlo con varnish.


El punto de entrada de la solución es varnish quien atiende al puerto 80 como si del servidor principal se tratara. En el puerto 81 estará corriendo nginx quien redireccionará todas las request que varnish no tenga en cache al servidor origen correcto, mediante proxy_pass.
Primero el fichero de configuración de varnish.

# Backends
backend default {
  .host = "127.0.0.1";
  .port = "81";
}
# ACL Purge
acl limpia {
      "localhost";
      "10.90.90.0"/24;
      "10.90.40.0"/24;
      "10.90.55.0"/24;
} 
sub vcl_recv {
   # Metemos el X-Forwarder-for
   set req.http.X-Forwarded-For = client.ip;
   # Si el backend tarda mucho en generar la pagina sirve el objeto expirado.
   set req.grace = 2m;
   # Si el metodo no es el esperado no lo permitimos
   if (req.request != "GET" &&
     req.request != "HEAD" &&
     req.request != "POST" &&
     req.request != "PURGE") {
error 405 "Method Not Allowed";
   }
   # Dejamos pasar el POST sin cachear
   if (req.request == "POST") {
       return (pass);
   }
  # Filtro de purgado
  if (req.request == "PURGE") {
      if (!client.ip ~ limpia) {
          error 405 "Method Not Allowed";
      }
      return(lookup);
  }
   # La autenticacion la dejamos pasar hasta el backend sin cachear
   if (req.http.Authorization) {
       /* Not cacheable by default */
       return (pass);
   }
  # Si la peticion tiene cookie la cacheamos igualmente.
  if (req.request == "GET" && req.http.cookie) {
    return(lookup);
  }
   return (lookup);
}
sub vcl_hit {
   if (!obj.cacheable) {
       return (pass);
   }
   if (req.request == "PURGE") {
      set obj.ttl = 0s;
      error 200 "Purged.";
  }
   return (deliver);
}
sub vcl_hash {
      if (req.http.Accept-Encoding ~ "gzip") {
              set req.hash += "gzip";
      }
      else if (req.http.Accept-Encoding ~ "deflate") {
              set req.hash += "deflate";
      }
}
sub vcl_miss {
  if (req.request == "PURGE") {
 error 404 "Not in cache.";
  }
}
sub vcl_fetch {
   # Si el backend tarda mucho en generar la pagina sirve el objeto expirado.
   set beresp.grace = 2m; 
   if (beresp.http.Set-Cookie) {
       return (deliver);
   }
  # No cachear si tenemos autorizacion
  if (req.http.Authorization) {
      return(pass);
  }
  # No cachear si lo dice cache-control
  if( beresp.http.Pragma ~ "no-cache" ||
      beresp.http.Cache-Control ~ "no-cache" ||
      beresp.http.Cache-Control ~ "private" ||
      beresp.http.Cache-Control ~ "max-age=0" ||
      beresp.http.Cache-Control ~ "must-revalidate" ||
      beresp.http.Cache-Control ~ "no-store" ||
      beresp.http.Cache-Control ~ "private" ) {
      return(pass);
  }
   return (deliver);
}
sub vcl_deliver {
   if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
   } else {
        set resp.http.X-Cache = "MISS";
   }
   return (deliver);
}
sub vcl_error {
   set obj.http.Content-Type = "text/html; charset=utf-8";
   synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
 <head>
   <title>"} obj.status " " obj.response {"</title>
 </head>
 <body>
   <h1>Error "} obj.status " " obj.response {"</h1>
   <p>"} obj.response {"</p>
   <h3>Guru Meditation:</h3>
   <p>XID: "} req.xid {"</p>
   <hr>
   <p>Varnish cache server</p>
 </body>
</html>
"};
   return (deliver);

}
Como se ve en las primeras lineas del fichero de configuración defaul.vcl estamos poniendo como backend el nginx que corre en el puerto 81.
Ahora el fichero de configuración del nginx:

user  nobody nogroup;
worker_processes  1;
error_log  logs/error.log;
events {
  worker_connections  1024;
}
http {
  include       mime.types;
  default_type  application/octet-stream;
  sendfile        on;
  keepalive_timeout  65;
  upstream origen1 {
      server origen.prueba.com:80; 
  }
  upstream origen2 {
      server origen2.example.com:80; 
  }
  server {
      listen       81;
      server_name  www.prueba.com;
      location / {
              proxy_set_header  X-Real-IP  $remote_addr;
              proxy_set_header Host $http_host;
              proxy_pass http://origen1;
      }
  }
  server {
      listen       81;
      server_name  www.example.com;
      location / {
              proxy_set_header  X-Real-IP  $remote_addr;
              proxy_set_header Host $http_host;
              proxy_pass http://origen2;
      }
  }
}

En la configuración del nginx estamos definiendo varios servidores origen en funcion de la request que le esté pasando el varnish.

Por último solo nos queda probar que todo funciona como debe.

Comments 0

Add Comment