lunes, 11 de abril de 2011

Cache Multisite


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.

miércoles, 6 de abril de 2011

Controlar la actividad de los usuarios con snoopy

A todo Administrador, alguna vez le ha surgido la necesidad de saber quien ha borrado el fichero de turno, si hay algún usuario más listo de la cuenta o por que no, por que mola saberlo.

Pues bien, mediante esta fácil solución podemos conocer los comandos que ha ejecutado un usuario en todo momento.

Para ello necesitamos instalar la librería de snoopy.
apt-get install snoopy
Cuando instalas por defecto te mete en /etc/ld.so.preload la linea /lib/snoopy.so, debemos comentarla si no queremos que nuestro sistema este logando sin parar la actividad de todos los usuarios del sistema y cuando digo todos, digo todos, daemon, www-data, tomcat, etc (que en algún caso también podría resultarnos de gran utilidad, pero no es el caso).
Una vez en este punto creamos el script /bin/snoopy_bash con el siguiente contenido y le damos permisos de ejecución (755):
#!/bin/bash
# Bash que loga la actividad de los usuario
export LD_PRELOAD=/lib/snoopy.so
/bin/bash
 
 
 
chmod 755 /bin/snoopy_bash
Solo nos queda cambiar el bash por defecto que use el usuario que queremos controlar en el fichero /etc/passwd y ver como todos los comandos que este usuario ejecuta se van quedando en el /var/log/auth.log
pruebas:x:1012:1002::/home/pruebas:/bin/snoopy_bash