Full text
Escola Tècnica Superior d’Enginyeria Informàtica Universitat Politècnica de València Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web. Trabajo Fin de Grado Grado en Ingeniería Informática Autor: Pablo Álvarez Baeza Tutor: Julio Pons Terol 2014/2015
2
Resumen La utilización de un proxy inverso es una técnica que permite mejorar prestaciones y reducir la carga de los servidores mientras que se mantiene compatibilidad con los servidores web más populares, como por ejemplo Apache. Virtualmin GPL es un panel de control y gestor de plataformas webs, opensource, que permite crear y configurar de forma automática todos los recursos asociados con un hospedaje web basado en el servidor Apache. El objeto de este proyecto es instalar este software en un servidor e integrarlo con el proxy inverso Varnish Cache de forma que se pueda gestionar desde el panel de control Virtualmin. El desarrollo se ha realizado en máquinas virtuales para tener mayor flexibilidad. Inicialmente, se han realizado configuraciones manuales, se han afinado los parámetros de configuración y posteriormente se han diseñado scripts de automatización. Se ha utilizado el S.O. Linux con distribución CENTOS. Palabras clave: proxy inverso, Varnish Cache, panel de control, Virtualmin, hospedaje Web, Apache, CentOS. Abstract The usage of an inverse proxy on a server, usually leads to an improvement on the server performance and a reduction of the server load, while keeping system's compatibility with the most popular web serves such as Apache. Virtualmin GPL is a web hosting, opensource, control panel for Linux and UNIX systems, which allows to automatically configure every web hosting-related resource on a system based on Apache web server. The objective of this project is to install this software on a server, and integrate it with Varnish Cache reverse proxy, giving the administrator the tools for controlling everything directly from Virtualmin. We will be using virtual machines in order to improve flexibility in the development process. This project will be developed in CentOS Linux distribution. Keywords : Varnish cache, Apache, virtual server, Python, Virtualmin, Webmin, integration, reverse proxy. 3
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 4
Índice 1.Introducción.....................................................................................9 1.1.Objetivo.....................................................................................................10 2.Entorno de trabajo........................................................................11 2.1.Sistema operativo CentOS.........................................................................11 2.2.Lenguaje Python........................................................................................11 2.3.Servidor web Apache.................................................................................12 2.4.Panel Virtualmin........................................................................................14 2.5.Varnish Cache............................................................................................14 3.Planificación de la solución...........................................................17 3.1.Situación de partida....................................................................................17 3.2.Situación objetivo......................................................................................18 3.2.1Proxy..................................................................................................................18 3.2.2Proxy inverso.....................................................................................................19 4.Conceptos previos al desarrollo....................................................21 4.1.Panel Virtualmin........................................................................................21 4.2.Servidor web Apache.................................................................................24 4.3.Varnish Cache............................................................................................25 4.3.1Configuración del servicio................................................................................26 4.3.2Arquitectura del servicio...................................................................................26 5.Desarrollo del módulo...................................................................29 5.1.conf.file......................................................................................................29 5.2.varnishRLib.py..........................................................................................33 5.3.apacheConf.py...........................................................................................34 5.4.VarnishApache.py......................................................................................38 5.5.index.cgi.....................................................................................................42 5
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 5.6.Startstop.cgi...............................................................................................44 5.7.settings.cgi.................................................................................................45 5.8.settingsSave.cgi..........................................................................................47 5.9.applySettings.cgi........................................................................................47 5.10.editFile.cgi...............................................................................................49 5.11.editFileSave.cgi........................................................................................50 5.12.module.info / install_check.pl..................................................................52 5.13.Fichero varnish.........................................................................................53 5.14.Generación e instalación del módulo.......................................................53 6.VCL................................................................................................59 6.1.Disponibilidad de las variables en VCL.....................................................60 6.2.Backend y heath-checks.............................................................................62 6.2.1Código por defecto............................................................................................63 6.3.vcl_recv......................................................................................................63 6.3.1Código por defecto............................................................................................65 6.4.vcl_fetch....................................................................................................66 6.4.1Código por defecto............................................................................................67 6.5.vcl_hash.....................................................................................................67 6.5.1Código por defecto............................................................................................68 6.6.vcl_hit........................................................................................................68 6.6.1Código por defecto............................................................................................69 6.7.vcl_miss.....................................................................................................69 6.7.1Código por defecto............................................................................................69 6.8.vcl_pass......................................................................................................69 6.8.1Código por defecto............................................................................................70 6.9.vcl_deliver.................................................................................................70 6
6.9.1Código por defecto............................................................................................71 6.10.vcl_error...................................................................................................71 6.10.1Código por defecto..........................................................................................71 7.Pruebas de funcionamiento..........................................................73 7.1.Pruebas de funcionamiento del módulo.....................................................73 7.2.Pruebas de funcionamiento de la cache......................................................77 7.2.1Pruebas de acierto / fallo de la cache.................................................................77 7.2.2Pruebas de heath-check.....................................................................................79 8.Conclusión......................................................................................83 8.1.Trabajo futuro............................................................................................83 9.Referencias.....................................................................................85 7
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 8
1. Introducción De un sitio web en 1991, a mil millones de webs activas. Es la cifra máxima que, según NetCraft[1], se alcanzó en octubre del pasado año 2014. Desde entonces la cifra se ha mantenido estable, bajando la cuenta a más de 950 millones debido a las diferentes fluctuaciones de las estadísticas producidas por sitios web inactivos. Sin embargo se estima que la cifra vuelva a alcanzar ese pico y lo supere de manera estable a lo largo del próximo año. Y es que las páginas web, desde su aparición a los principios de los años 90, han conseguido entrar de lleno en nuestro día a día ofreciendo soluciones en prácticamente todos los campos imaginables. Hoy en día es realmente complicado encontrar a un ciudadano medio que no sea capaz de citar una web de noticias, de música, de interacción social o de una empresa, incluso aunque el campo de negocio de ésta sea ajeno al mundo de las tecnologías de la información. Y detrás de cada sitio web hay uno o varios servidores web ofreciendo todo tipo de contenidos las 24 horas al día los 365 días al año. Estos servidores web ejecutan una aplicación también denominada servidor web que se encargan de atender y procesar las peticiones que le llegan desde Internet a su dirección IP. El trabajo de estas aplicaciones a grandes rasgos es entender la petición, buscar en el disco el objeto que se está solicitando y enviarlo a través de la red. Es en este punto donde aparecen los programas conocidos como proxies inversos. Estos programas se colocan entre el servidor web e Internet, recibiendo todas las peticiones dirigidas al servidor. Almacenan la petición y la reenvían al servidor web, el cual le remitirá la respuesta correspondiente. Entonces, el proxy inverso almacena el par petición-respuesta y mantiene la información en cache. De esta forma, si vuelve a llegar al servidor la misma petición, en cuanto la intercepte el proxy, será él el que 9 Ilustración 1: Gráfica de sitios web en el mundo según Netcraft.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 16
3. Planificación de la solución Lo más importante para resolver un problema es hacer un correcto planteamiento previo, tanto del problema a resolver como de la solución que se va a desarrollar. Remitiéndonos al apartado de objetivo de esta memoria procedemos a recuperar la información de la necesidad para detallarla de una forma más concreta. El objetivo del proyecto es conseguir integrar Varnish para que funcione correctamente con un servidor web apache, creando un módulo para Virtualmin que permita al administrador web configurar de una forma cómoda los parámetros básicos de la integración. 3.1. Situación de partida El sistema operativo de la máquina virtual cuenta con un servidor web Apache ya instalado, así como con un panel de control Virtualmin. El servidor web Apache se encuentra activo, escuchando las peticiones HTTP que le lleguen por el puerto 80 a la dirección IP de la máquina, que en nuestro caso es la dirección IP 192.168.0.103. 17 Ilustración 3: Esquema del estado inicial de nuestro sistema.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web El panel Virtualmin se encuentra también activo, siendo accesible por el puerto 10000 del servidor. Para conectarse hay que acceder con un navegador web con soporte para HTTPS y autenticarse como usuario válido del sistema CentOS. Se usará root para tener los permisos administrativos necesarios. Se trata de una configuración típica y sencilla de un servidor web genérico, sin ningún proxy instalado. Por este motivo, en este caso es Apache el que recibe, procesa y responde todas las peticiones web que le lleguen por el puerto estándar de HTTP, el puerto 80. 3.2. Situación objetivo A continuación vamos a explicar cómo deberá de quedar el sistema una vez se ejecute nuestra solución de integración de manera correcta. Para ello, antes de nada, explicaremos a groso qué es y como funciona tanto un proxy como un proxy inverso. 3.2.1 Proxy Un proxy, o servidor proxy, en una red informática, es un servidor (un programa o sistema informático), que sirve de intermediario en las peticiones de recursos que realiza un cliente a un servidor (nuestra máquina con Apache). Por ejemplo, si una hipotética máquina A solicita un recurso a C, lo hará mediante una petición a B (el proxy), que a su vez trasladará la petición a C; de esta forma C no sabrá que la petición procedió originalmente de A. Esta situación estratégica de punto intermedio suele ser aprovechada para soportar una serie de funcionalidades: control de acceso, registro del tráfico, prohibir cierto tipo de tráfico, mejorar el rendimiento, mantener el anonimato, proporcionar cache web, etc; este último sirve para acelerar y mejorar la experiencia del usuario mediante elementos de la web que guardará el proxy, esto se debe a que la próxima vez que se visiten las páginas web no se extraerá información directamente del servidor web, si no que se recuperara información de la cache. 18 Ilustración 4: Esquema de un proxy situado a la salida de una intranet.
La situación más típica para un proxy es a la salida de una red interna hacía Internet, proporcionando a los usuarios de esta intranet una puerta de salida hacía el exterior. De esta forma se consigue controlar todo el tráfico de salida si se desea, pues debe de pasar por el proxy. Así también se pueden reducir tiempos de navegación, pues sí el proxy tiene almacenado en cache el objeto solicitado desde la red interna, éste lo servirá rápidamente, sin necesidad de enviar la petición al servidor externo y esperar su respuesta. 3.2.2 Proxy inverso Cuando hablamos de un proxy inverso, nos referimos a un proxy que se sitúa entre uno o varios servidores web e Internet. Gracias a esta arquitectura de red, los servidores quedan protegidos de ataques externos, pues es el proxy el que puede controlar y filtrar todas las peticiones entrantes. Sí además añadimos la característica de proxy cache inverso, conseguiremos librar a los servidores de la carga que supondría el procesado de todas las peticiones que ahora son respondidas desde este intermediario. De cara al cliente, todo este proceso es transparente, y no podrá distinguir si el que le sirve la petición es el servidor o el proxy. Con los conceptos anteriores claros, a continuación concretamos cómo queda nuestra máquina y sus conexiones una vez realizada la integración de Apache con Varnish mediante Virtualmin. Al ser el proxy inverso el que debe recibir las peticiones HTTP, deberá escuchar hacía Internet en el puerto 80. Por consiguiente, dado que ejecutaremos en la misma máquina los servicios de Apache y de Varnish, deberemos mover Apache de ese puerto y colocarlo en otro en el que no tenga conflicto con otros servicios. Típicamente y como buena práctica, apache se suele colocar en el puerto 8080 y en la dirección local loopback o localhost, ésta es la 127.0.0.l. De esta forma evitaremos que nadie pueda atacar el servidor web directamente desde el exterior de la máquina. Por último deberemos configurar Varnish para que sepa en qué dirección y puerto está Apache, para así poder retransmitirle las peticiones cuando sea necesario. 19 Ilustración 5: Esquema de un proxy inverso.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web De esta forma, en la situación final, ante una petición HTTP entrante, Varnish será el encargado de recibirla y procesarla. Entonces reenviará la susodicha petición procesada a Apache. El servidor entonces responderá a la petición con el o los objetos necesarios que serán recibidos por Varnish. En este momento el proxy almacenará en cache el par petición/respuesta al mismo tiempo que envía los objetos a la dirección que originó la petición. Ahora, ante una petición entrante que tenga que recibir la misma respuesta, será Varnish el que la responda directamente con los objetos que tenga en cache sin necesidad de que Apache reciba ni procese nada, alcanzando así la consiguiente reducción de carga al sistema y evitando los tiempos de procesado de peticiones de Apache, que son superiores a los de Varnish. 20 Ilustración 6: Esquema de la situación de nuestro sistema una vez completado el objetivo.
4. Conceptos previos al desarrollo Una vez planificada la solución que se busca, se ha procedido a estudiar de forma exhaustiva los diferentes integrantes software del proyecto, con el fin de conocer sus formas de funcionamiento, ficheros de configuración, lógicas de trabajo y demás factores clave que hay que conocer para poder abordar el desarrollo de forma eficaz.. 4.1. Panel Virtualmin En primer lugar vamos a explicar cómo se puede acceder al panel de control desde una máquina remota. Es el paso esencial para poder utilizarlo como administradores. Aunque pueda resultar algo trivial, la máquina debe estar arrancada y funcionando, así como conectada a la red con una configuración válida. Entonces, sí en el equipo se encuentra instalado el panel Virtualmin y se encuentra lanzado el servicio (cosa que se hace por defecto al arranque del sistema), desde un navegador externo deberemos introducir la dirección IP de nuestro servidor e indicar que la conexión se realice por el puerto 10000. También se debe de usar una conexión con SSL, es decir, habrá que introducir la siguiente dirección en el navegador: •https://192.168.0.103:10000 Una vez lancemos la petición a esa dirección, nos aparecerá una ventana de login a través de la cual podremos acceder al panel y a todas sus funciones ingresando nuestras credenciales, como la que se muestra en la figura 7. 21 Ilustración 7: Pantalla de acceso al panel webmin.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Estas credenciales son las mismas que se utilizan para iniciar sesión en el sistema operativo, por lo que nuestro usuario y contraseña deberán estar dados de alta en nuestro CentOS, y por ende, al ser una distribución Linux, deberán existir en el fichero /etc/passwd donde se almacenan todos los usuarios creados y sus propiedades. Una vez autenticados en la ventana de login, en la máquina se lanza el ejecutable encargado de leer la configuración del panel y representar la información en una página web html. Remarquemos que cuando un ejecutable trabaja de esta forma, es decir, procesando información en el servidor y generando al vuelo código HTML (o cualquier otro objeto MIME) para ser representado en un navegador, se le denomina CGI (Common Gateway Interface ). Esta es la forma general de trabajar del panel de control en todas las situaciones de interacción. Cuando el administrador hace clic sobre los elementos de la página del panel, el sistema no hace más que lanzar a ejecutar los CGIs asociados a esas acciones que se encargan de procesar la información en el servidor y generar el código de la página web correspondiente que se muestra en el navegador. Estos ejecutables de los paneles se componen de instrucciones escritas en Perl, un lenguaje de programación interpretado, que el servidor traduce a código máquina y ejecuta, y obteniendo como resultado una página de código HTML que el sistema envía al navegador origen de la petición. Aunque la gran mayoría de los CGIs de Virtualmin estén escritos en Perl, si nos interesa desarrollar a nosotros mismos algún módulo o función extra, podremos hacerlo en cualquier lenguaje interpretado, siempre y cuando la máquina en la que se ejecute disponga del intérprete correspondiente para el lenguaje escogido. En segundo lugar, se ha analizado y estudiado la herramienta Virtualmin. El objetivo es conocer a fondo los diferentes ficheros que emplea para almacenar toda la información de configuración de los diferentes servidores virtuales que administra. También debemos conocer los diversos ejecutables que se lanzan cuando el administrador ejecuta acciones sobre la interfaz web del panel de control. Gracias a estos conocimientos, hemos podido diseñar nuestra solución para que sea capaz de interoperar con Virtualmin sin perjudicar el correcto funcionamiento tanto del panel como de los servicios que tenga activos el propio servidor en la situación previa a la integración. El primer paso es localizar el directorio raíz del panel, para así poder analizar posteriormente su contenido. Recordamos que Virtualmin es una extensión del panel de control Webmin, al que le añade la capacidad de gestionar servidores virtuales. Por lo tanto parece razonable buscar nuestro objetivo dentro de la familia de directorios de Webmin. De esta forma el directorio donde se instala Virtualmin en nuestro sistema CentOS es: •/usr/libexec/webmin/virtual-server/ Como curiosidad, podemos apreciar que el propio nombre del directorio unicamente hace referencia a la funcionalidad que el panel añade a Webmin. En el interior de este directorio raíz de Virtualmin se encuentran los archivos ejecutables que se lanzan cada vez que el administrador realiza alguna acción en el panel. También se localizan aquí los diferentes ficheros de configuración de esos ejecutables así como diversos ficheros necesarios para que Virtualmin funcione en sinfonía con Webmin. 22
De entre todos los ficheros, el más importante para el desarrollo de nuestro proyecto es el dichero config. Éste contiene una extensa lista de atributos de configuración, entre los que se pueden encontrar desde parámetros por defecto de configuración de puertos en los servidores virtuales hasta rutas de ficheros que debe conocer el panel. Los atributos se organizan de forma que al principio de cada linea aparece el nombre de la propiedad y a continuación, precedido por un símbolo “=” se encuentra el valor o los diferentes valores separados por comas en el caso de que fuera un atributo multivaluado. Cada vez que un ejecutable del panel realiza una llamada a la función init_config(), ésta carga en memoria todos los atributos ordenados como una lista de pares clave/valor para así poder ser leídos o escritos correctamente por los programas del módulo que lo necesiten. El contenido del fichero se puede editar a través de diversos formularios que muestra el panel al administrador en las secciones correspondientes a cada familia de valores, pero si se desea también se puede editar a mano, y mientras los valores introducidos sean coherentes el funcionamiento del panel será el correcto. Una función importante de Virtualmin y que nos interesa conocer es que a la hora de crear un nuevo servidor virtual, ofrece al administrador una plantilla con los parámetros por defecto entre los que se encuentran el puerto e IP de este servidor. Esto, unido al esquema final que queremos conseguir para el sistema hace que nuestra solución deba cambiar esa plantilla con los nuevos valores de comunicaciones para que coincidan con la dirección y puerto al que moveremos Apache. Todos los atributos por defecto de esta plantilla se encuentran en el fichero config de configuración mencionado con anterioridad. 23 Ilustración 8: Extracto del fichero conf de Virtualmin
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 4.2. Servidor web Apache Tras analizar y comprender el panel Virtualmin y su funcionamiento, toca estudiar el servidor web Apache, qué recordemos, es el que se encarga en la situación inicial de recibir, procesar y responder las peticiones que le lleguen a través de la IP en la que esté configurado. En el sistema de nuestra máquina virtual se encuentra instalado un servidor Apache versión 2.2. El directorio raíz del programa es: •/etc/httpd/ Dentro de este directorio hay dos directorios clave para nosotros que son: •/etc/httpd/conf/ •/etc/httpd/conf.d/ Dentro del primer directorio están los ficheros de configuración del servicio web que ofrece Apache. De todos ellos el archivo más importante es httpd.conf que contiene todos los atributos de configuración del servicio. En este fichero podemos encontrar, entre otros atributos, el puerto o puertos y dirección o direcciones IP en los que Apache se encuentra escuchando a la espera de peticiones entrantes. También se especifican aquí en qué rutas del sistema debe ir Apache a buscar los objetos necesarios para responder una petición. Además, en el fichero se encuentra definido cualquier servidor virtual que exista en la máquina. Apache sigue el mismo formato para todos sus ficheros de configuración, incluido del que estamos tratando. Un atributo de configuración ocupa una linea, y los valores que tenga definido este atributo deben escribirse a continuación en la misma línea, separados del atributo por un espacio. Sí el valor de un atributo contiene espacios, es necesario escribirlo entrecomillado con comillas dobles. Las líneas más importantes en relación a nuestro proyecto son dos: •Listen 80: Este atributo especifica en qué IP y puerto está escuchando el servidor Apache a la espera de peticiones. En este caso vemos que Apache espera en todas las IP disponibles y en el puerto 80. También podrían haber otros formatos de línea coexistiendo, como Listen IP:puerto, o Listen *:puerto. •NameVirtualHost *:80: Esta linea indica en qué dirección IP y puerto espera Apache peticiones que se van a enviar a los hosts virtuales. El * indica que se esperan peticiones en todas las direcciones IP disponibles en la máquina. Los atributos del fichero pueden agruparse en bloques de configuración, especificando así a qué parte concreta del servidor se aplican esos valores contenidos en el bloque. Estos apartados se organizan siguiendo una estructura en formato XML, es decir, se delimitan al inicio y al final por una línea con el nombre del bloque entre los caracteres menor y mayor que (<, >). En el fichero se pueden encontrar bloques de configuración de los siguientes tipos: <Directory>, <DirectoryMatch>, <Files>, <FilesMatch>, <Location>, <LocationMatch>, y <VirtualHost>. Este ultimo tipo de bloques de configuración son los que más nos interesan de cara al proyecto, pues como se puede deducir a partir de la etiqueta que los identifica, cada uno contiene la configuración de cada servidor virtual alojado en el servidor web. 24
Un servidor virtual es una partición dentro de un servidor web físico (una máquina con Apache en nuestro caso) que puede convivir funcionando simultáneamente con otros servidores virtuales. Gracias a esta abstracción, con una única máquina y un único servidor Apache podemos ofrecer al exterior el servicio de tantos servidores como deseemos, sin que el usuario note que están todos en un único ordenador. Pero entonces los servidores virtuales deben diferenciarse unos de otros y tener una identificación única que permita a Apache decidir a qué servidor concreto va destinada una petición entrante en la máquina. Esta diferenciación o identificación se puede conseguir mediante el nombre de host. Esto quiere decir que si por ejemplo tenemos un servidor virtual con el atributo de configuración ServerName con valor “ejemplo.com”, cuando llegue una petición web a Apache, éste mirará la cabecera host de la petición, y si coincide con el valor del atributo mencionado, se asignará esa petición a ese servidor virtual. También es posible hacer esta diferenciación entre servidores virtuales utilizando diferentes direcciones IP y/o puertos para cada host virtual. De esta forma, si una petición entra por la IP y puerto que tenga asignado un servidor virtual, será a este al que Apache mandará la petición. Volviendo al estudio de los directorios de Apache, pasamos ahora a /etc/httpd/conf.d/ en el que se encuentran los ficheros de configuración que utilizan los módulos de Apache instalados en el equipo. Por ejemplo la extensión mod_dbd que añade a Apache la posibilidad de utilizar conexiones con una base de datos SQL. Existen numerosos módulos o extensiones para Apache, convirtiéndolo aún más si cabe en una auténtica navaja suiza de los servidores web[19]. 4.3. Varnish Cache En esta sección estudiamos la herramienta que hace de proxy inverso en nuestro sistema. Vemos como funciona y cómo se configura para poder abordar posteriormente el desarrollo de la solución de la mejor forma posible. Comenzamos con todo lo referente a la configuración de Varnish y observamos que existen dos grandes categorías de configuración en el programa, la configuración por linea de comandos con los parámetros del servicio, y el fichero VCL, qué configuraremos más adelante. 25 Ilustración 9: Ejemplo de bloque de configuración de un virtual host. <VirtualHost 127.0.0.1:8080> SuexecUserGroup "#513" "#511" ServerName prueba.com ServerAlias www.prueba.com ServerAlias webmail.prueba.com ServerAlias admin.prueba.com DocumentRoot /home/prueba.com/public_html </VirtualHost>
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web •varnishListenPort: 80 Puerto en el que vamos a poner Varnish a escuchar peticiones. El puerto recomendado es el puerto HTTP, es decir, el puerto 80 que coincide con el valor por defecto. •varnishAdmListenAdd: 127.0.0.1 Dirección IP por la cual se podrá acceder a la consola de administración de Varnish. Se recomienda una dirección de la cual tengamos la certeza de que solo el administrador podrá tener acceso. Por defecto viene la dirección loopback 127.0.0.1, lo que nos confiere la seguridad de que solo se podrá acceder a este servicio a través de la propia máquina. •varnishAdmListenPort: 6082 Puerto a través del cual se podrá acceder a la consola de administración de Varnish. El valor por defecto es el que se recomienda en la documentación del programa por convención. •varnishStorageSize: 400M Tamaño del espacio de memoria que Varnish va a reservar para la cache. Se pueden utilizar los sufijos k (kilobytes), M (megabytes), G (gigabytes) y T (terabytes). El valor por defecto es 400M, pero deberá ser modificado por el administrador para ajustarse a sus necesidades y limitaciones. Se hablará más adelante de este aspecto. •varnishStorage: malloc,${VARNISH_STORAGE_SIZE} Forma de reservar memoria para cache de Varnish. El valor por defecto es con un malloc del tamaño especificado en parámetro anterior. Se deberá modificar este valor por medio de un editor de texto si se desea reservar la memoria para cache con un fichero, pero no es una práctica recomendada pues perdemos parte importante de la mejora de rendimiento. •varnishTTL: 120 Tiempo de vida (en segundos) durante el cual se mantendrán los objetos en cache. Por defecto se aplican 120 segundos, que es la configuración con la que se instala el software Varnish. El administrador deberá cambiar este atributo mediante el formulario diseñado para ello y adaptarlo a sus necesidades. •varnishMinH: 50 Número mínimo de hilos que mantendrá Varnish en espera por cada pool de hilos. Por defecto se ha decidido dejar 50 hilos siempre activos, pero el valor puede ser cambiado por el administrador en el formulario para adaptar la solución a sus niveles de tráfico. Recordemos que Varnish trabaja con 2 pools de hilos por defecto siendo esta la configuración más recomendada. 32
•varnishMaxH: 1000 Número máximo de hilos que Varnish podrá tener en ejecución por cada pool de hilos. Por defecto hemos asignado un valor de 1000 hilos, que combinado con los dos pool con los que trabaja Varnish por defecto, hacen un total de 2000 hilos como máximo simultáneos, lo que se traduce en un máximo de 2000 peticiones atendidas simultáneamente. El valor podrá ser editado por el administrador a través del formulario. 5.2. varnishRLib.py Después de explicar cómo vamos a guardar las configuraciones de nuestro módulo a través del fichero descrito anteriormente, procedemos a desmembrar y analizar la librería que hemos creado en Python varnishRLib.py. Podemos ver un extracto del código del fichero en la siguiente imagen. Dentro de este fichero encontramos todas las funciones que tienen en común los distintos ejecutables del proyecto, es por ésto por lo que podemos denominar al fichero como una librería. Dentro del fichero podemos encontrar funciones para leer nuestro archivo de configuración o también para escribirlo. Las detallamos a continuación. •guardaConf( ) Función que abre el fichero de configuración conf.file y lo recorre línea a línea, comparando las entradas con las de la variable config, escribiendo los valores de esta variable en la línea correspondiente. 33 Ilustración 11: Extracto de código de la funcion cargaConf de la librería de nuestro módulo. ############################################################################ # Funcion que lee el fichero conf.file para cargar la configuracion # de los script y la guarda en el diccionario global "config" ############################################################################ def cargaConf ( ): f=open("conf.file","r") lineas=f.readlines() f.close() valores=[] for linea in lineas: fin=linea.find(":") valores=re.split("(\s)+",linea) #guarda parametros valores=valores[1:] # quita el primer espacio valores=valores[1::2] # quita el resto de espacios. config[linea[0:fin]]=valores #asigna la de conf
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web •cargaConf( ) Función que abre el fichero de configuración y lo recorre línea a línea, cargando los valores encontrados en la variable config. •imprimeConf( ) Función que recorre el fichero de configuración e imprime los distintos valores de configuración encontrados. •log (cadenaLog) Función que abre un fichero de log llamado logFile.log para escribir en éste el valor de la variable que se le pasa como argumento, precedido de la hora del sistema en el momento de la escritura. Gracias a esta función se mantiene un registro de las acciones realizadas por los ejecutables para facilitar la tarea de debug. •escribeFichero (fich, conf) Función que abre el fichero que se le pasa como parámetro a través de la variable fich, para posteriormente, añadir al final del mismo el contenido de la variable que se le pasa como parámetro conf. También genera una linea de log al ejecutarse indicando qué fichero se ha escrito. •leeFichero (fich, conf) Función que abre el fichero que se le pasa como parámetro a través de la variable fich, para recorrerlo línea a línea. Devuelve el contenido del fichero leído en la variable contenido. Esta función también genera una entrada de log indicando qué fichero se ha leído. El mecanismo para poder cargar y utilizar estas funciones en cualquier ejecutable es utilizar la instrucción import varnishRLib.py, de esta forma, la librería se enlaza con el ejecutable que la importa, permitiendo la llamadas a sus funciones dentro del código mediante la instrucción varnishRLib.función(parámetros de entrada), que veremos aparecer numerosas veces en los otros ejecutables. 5.3. apacheConf.py Sobre este script recaen las funciones iniciales para preparar el servidor Apache para la integración de nuestro proxy inverso. A continuación se detalla el contenido de las funciones que lo componen así como su cometido, adjuntando alguna imagen que ayude al lector a visualizar el código programado. 34
•compruebaConfApache( ) Esta función se encarga de abrir el fichero de configuración de apache, que se encontrará en la ruta especificada por el valor de nfConApache de nuestro fichero de configuración, y de cargar su contenido en una variable. Posteriormente envía ese contenido a la función ConfApache( ), la cual realizará las modificaciones necesarias que veremos más adelante en esta misma sección de la memoria. Después mandará ese contenido del fichero de configuración modificado a la función purgarApache( ), que realizará otras modificaciones en el contenido. Por último, si se ha modificado algo del fichero, la función lo guardará en su sitio con el nuevo contenido modificado. •confApache (conf) La función de la que tratamos ahora, recibe como parámetro una variable cargada con el contenido del fichero de configuración de Apache. La llamada la recibe de la función que acabamos de analizar anteriormente. Su funcionamiento consiste en recorrer esa configuración línea a línea para, mediante el uso de expresiones regulares, buscar las entradas que indican en qué dirección o direcciones IP y puerto o puertos se encuentra el servidor web Apache esperando conexiones entrantes. En primer lugar se buscan las entradas de tipo “NameVirtualHost IP:puerto”, de las cuales se extrae tanto el puerto como la IP que contienen para compararlos con los valores de dirección a los que se desea mover el servidor web Apache. En el caso de que no sean los valores deseados se cambia la línea con los nuevos valores de IP y puerto. Lo mismo se hace con las entradas tipo “Listen IP:puerto” y sus posibles variaciones que pueden ser tanto “Listen puerto” como “Listen *:puerto”. En todos los casos citados se sustituye tanto el puerto como la dirección IP por los valores configurados en el módulo. Por último se localizan las entradas del fichero de tipo “<VirtualHost IP:puerto>” para proceder a cambiar el puerto de los servidores virtuales por el puerto configurado para Apache. Durante la ejecución de la función, se omitirán todas las entradas que mencionen el puerto SSL, es decir, el puerto 443, ya que Varnish no soporta ese protocolo por lo que los servicios que lo usen deberán continuar ejecutándose sin modificación alguna de sus comunicaciones. •purgarApache(conf ) A esta función se le llama inmediatamente después de que la función anterior realice las pertinentes modificaciones al fichero de configuración de Apache que recordemos se encuentra cargado en memoria en una variable. La utilidad del código de esta función es la de eliminar cualquier entrada de tipo “Listen IP:puerto” que se encuentre repetida a lo largo del fichero. De no hacerlo, al encontrarse Apache con más de una entrada de este tipo con la misma IP y puerto, no sería capaz de arrancar, dando un error en el servicio. Puede verse el código de esta función en la figura 12. 35
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web •comprobarVarnish( ) La sencilla tarea de esta función del script es la de comprobar si está actualmente Varnish instalado en la máquina. Para ello intenta abrir el fichero de configuración del servicio, devolviendo un valor False en caso de que no pueda encontrarlo o lo que desencadenará la ejecución de la siguiente función. •instalarVarnish( ) Tal y como se introducía antes, este segmento de código se lanza a ejecución en el caso de que la función anterior determine que Varnish no se encuentra instalado en el equipo. Al ejecutarse, la función instala el repositorio oficial del programa Varnish en su versión 3 para CentOS (o sistemas basados en RHEL). A continuación ejecuta la orden de instalación del programa y una vez completado este proceso, indica al sistema que este programa se lanzará al arrancar la máquina. Puede verse el código de esta función en la imagen 13. •comprobarRPAF( ) Esta función comprueba sí el módulo de Apache, RPAF, se encuentra instalado en el equipo o no. Para ello se basa en el mismo método que la función comprobarVarnish( ). •instalarRPAF( ) La función de encarga de descargar e instalar el módulo de Apache que le permitirá poder identificar el origen de las peticiones que le lleguen, tal y como se explica más adelante. •modPlantillaVmin( ) El código dentro de esta función se encarga de abrir el fichero donde se encuentra la información de la plantilla que ofrece Virtualmin al administrador del servidor a la hora de crear nuevos servidores virtuales y cargar el contenido en una variable, para posteriormente mandar el contenido a editar por otra función. Una vez finalizada la modificación, se procede a escribir el fichero con los nuevos valores en su sitio. •confPlantilla (conf) Esta función recibe como parámetro de entrada todo el contenido de del fichero indicado por el parámetro de configuración nfPlantilla. Recorre dicho contenido línea a línea buscando mediante el uso de expresiones regulares las entradas de tipo “web_port=” y “old_defip=”. Ambas entradas se sustituyen por el valor del puerto e IP al que se desea mover a Apache. De esta forma, cuando el administrador desee crear un nuevo servidor virtual, los valores por defecto que se le mostrarán para estos parámetros serán los deseados en la integración. 36
Una vez conocidas todas las funciones que componen el script, procedemos a justificar su utilización. Así tenemos que en primer lugar, para que la integración funcione correctamente, es estrictamente necesario mover al servidor web Apache del puerto 80 a otro puerto, pues en caso contrario se produciría un conflicto con el servicio Varnish, que debe atender peticiones del exterior en el puerto estándar de HTTP, esto es el puerto 80. Para conseguir mover el servicio es necesario cambiar todas las entradas “Listen” y “NameVirtualHost” encontradas en el fichero de configuración. De esta forma evitaremos los conflictos entre los servicios. En cuanto al módulo de Apache, RPAF, resulta necesario para que la integración con el proxy inverso resulte plenamente funcional. En una configuración estándar entre Apache y un proxy inverso, sin el módulo RPAF, las peticiones que le lleguen al servidor web tendrán como IP de origen la IP del proxy inverso, pues es donde se interceptan, se tratan y desde donde se reenvían a Apache. Ésto es lo que sucede a nivel de datagrama IP, y en realidad es la forma correcta de funcionar según la implementación del protocolo, por lo que la modificación de este comportamiento no se contempla sencilla. El principal inconveniente de esta situación es la generación y estudio de logs y ficheros de estadísticas desde Apache, pues de esta manera sería imposible identificar correctamente de qué cliente son las peticiones que recibe, apareciendo en todas nuestro proxy Varnish como origen de éstas. 37 Ilustración 12: Extracto de código del fichero apacheConf.py que ilustra la función purgarApache. ########################################################################### # Funcion que elimina las entradas Listen repetidas para evitar problemas de configuracion ########################################################################### def purgarApache (conf): configurado=False for n in range(0,len(conf)): linea=conf[n] if re.match("Listen \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{2,4}\n", linea): ini=linea.find(" ") fin=linea.find(":") IPantigua=linea[ini+1:fin] puertoAntiguo=linea[fin+1:len(linea)-1] if puertoAntiguo==varnishRLib.config["nPuertoAp"][0] and IPantigua==varnishRLib.config["IP"][0]: if configurado: conf[n]="" if not configurado: configurado=True return conf
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web La solución, en nuestro, caso pasa por recurrir al citado módulo RPAF. Este módulo nos permite poder añadir de forma programática una cabecera HTTP a las peticiones cuando pasan por el proxy inverso. En concreto la cabecera es la “X-Forwarded-For” y en ella se indica el valor de la dirección IP donde se originó la petición. Gracias a esta solución, Apache puede interpretar correctamente esa cabecera y consigue generar unos logs y unas estadísticas correctas que nos darán unos resultados verídicos, dando por solventado el problema. Más adelante, cuando veamos la configuración del funcionamiento de la cache de Varnish en el fichero VCL, veremos como incluimos esta cabecera a las peticiones procesadas. En lo referente al protocolo HTTPS, como ya se ha mencionado en anteriores ocasiones, el proxy Varnish no tiene compatibilidad con éste, por lo que a la hora de hacer la integración no se deberá tocar ninguna entrada de configuración que mencione el puerto 443. De esta forma se consigue que todas las web servidas a través de este puerto permanezcan intactas y ajenas a la instalación del proxy, funcionando con total normalidad. Por último, la mayoría de acciones que realiza el script generan una entrada en el fichero de log del módulo. Gracias a ésto, en el caso de que se produzca algún error durante la ejecución, será más sencillo localizar el fallo y corregirlo como se considere oportuno. 5.4. VarnishApache.py Pasamos ahora a comentar y estudiar el ejecutable que sigue a apacheConf.py según el orden lógico de ejecución. El script VarnishApache.py tiene como misión principal la de integrar el recién instalado Varnish con Apache, haciendo que el proxy envíe las peticiones HTTP al puerto y dirección IP a los cuales hemos movido el servidor web. Al igual que con los scripts anteriores, procederemos a detallar las diferentes funciones que componen el archivo en Python para más tarde justificar su utilización. 38 Ilustración 13: Función del ejecutable apacheConf.py que instala Varnish. ########################################################################## # Funcion que instala Varnish en el sistema. ########################################################################### def instalarVARNISH ( ): print "<br>"+"Instalando y configurando Varnish" varnishRLib.log("rpm --nosignature -i https://repo.varnishcache.org/redhat/varnish-3.0.el6.rpm\n") os.system("rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish3.0.el6.rpm") varnishRLib.log("yum install varnish\n") os.system("yum install varnish") varnishRLib.log("chkconfig varnish on\n")#Arranque varnish al arrancar la máquina os.system("chkconfig varnish on")
•mueveVirtualServers( ) Esta función se encarga de poner todos los servidores virtuales encontrados a lo largo del fichero de configuración de Apache en la dirección IP y puerto que el administrador haya indicado previamente en la configuración del módulo. Para ello, el código abre el fichero de configuración de Apache y lo recorre línea a línea comparando cada entrada mediante expresiones regulares, tal y como se ha hecho en situaciones anteriores. Se buscan todas las líneas del fichero que contengan la cadena “<VirtualHost IP:puerto>, para posteriormente identificar estos valores. En el caso de que el puerto del host virtual sea el 443, se procede a ignorar la entrada y no modificar nada debido a la incompatibilidad de Varnish con el protocolo HTTPS. Por el contrario, si el host no se encuentra en el puerto 443, se actualiza la entrada del fichero manteniendo el mismo formato pero con los valores para la dirección IP y el puerto correspondientes extraídos del fichero conf.file de nuestro módulo. La función también localiza y envía cada uno de los bloques de configuración de hosts virtuales a una función que se encargará de modificar las entradas customlog. Más adelante se puede observar una porción del código de esta función en la ilustración 14. •confCustomLog(bloque ) Esta función se encarga de buscar las entradas customlog dentro de un bloque de configuración de host virtual que se le pasa como argumento. Las entradas se cambian para enviar los archivos de los de cada servidor virtual al directorio raíz de Varnish Cache, identificando cada fichero con el nombre del host virtual para un mejor control de las estadísticas de cara a las tareas de administración. •creaVSconfVarnish( ) Este fragmento de código basa su funcionamiento en llamadas al sistema operativo. Lo que hace concretamente es, en primer lugar, copiar el fichero VCL genérico incluido por defecto en el módulo, a su ruta correspondiente. En segundo lugar, realiza la misma acción pero esta vez con el fichero de configuración del servicio Varnish. •crearBackend( ) Esta función es la responsable de conectar Varnish y Apache y lo consigue escribiendo en el fichero VCL del proxy inverso los valores de la dirección IP y puerto a los que se ha movido el servidor web. Se recorre el fichero de forma secuencial hasta encontrar la entrada “backend default{“ para añadir a partir de esa línea los valores correspondientes indicados en el fichero de configuración de nuestro módulo. Puede verse el código de esta función en la imagen 15. 39
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web •opcionesVarnish( ) El código Python dentro de esta función se encarga de escribir dentro del fichero de configuración del servicio de Varnish los valores que el administrador haya introducido en nuestro fichero de configuración (o los valores por defecto en caso de no modificarlo). Haciendo uso de expresiones regulares, busca las entradas correspondientes a “VARNISH_LISTEN_ADDRESS”, “VARNISH_MIN_THREADS”, VARNISH_MAX_THREADS”, “VARNISH_TTL”, “VARNISH_LISTEN_PORT”, “VARNISH_STORAGE_SIZE” y “VARNISH_STORAGE” y actualiza los parámetros dentro del fichero, escribiéndolo en disco con sus valores nuevos de configuración. •reiniciaServ( ) Para terminar, la función que tratamos en este punto se encarga de reiniciar los servicios de Apache y de Varnish con llamadas al sistema. Gracias a esto, las configuraciones aplicadas tienen efecto al momento. Una vez que conocemos las diferentes funciones que conforman este script, podemos concretar las tareas que se realizan al ejecutar este código y podemos razonar la necesidad de tales tareas. 40
En primer lugar, resulta necesario para una completa integración funcional el mover los servidores virtuales al nuevo puerto y dirección IP donde escucha Apache tras moverlo. De este modo, las peticiones web que entren en el servidor podrán llegar a ser atendidas por el host virtual correcto, ya que en el caso de que no coincidieran estos valores, no se podría comunicar peticiones a estas páginas web. Continuamos con las entradas custom log de los servidores virtuales. Un custom log es la forma que tiene Apache de generar información de acceso y de control sobre un servidor virtual, ya que de no utilizarlos, el log que se generase desde Apache sería compartido por todos los diferentes servidores virtuales que estuvieran alojados en nuestro equipo. Así, gracias a este mecanismo, el administrador puede tener unas estadísticas más específicas y podrá ejercer las tareas de administración de una forma más personalizada. 41 Ilustración 14: Extracto de código de la función mueveVirtualServers del ejecutable VarnishApache.py. ########################################################################### # Funcion que recorre el fichero de configuracion de apache buscando entradas de VirtualHost # para moverlos a la IP y puertos nuevos de apache. ########################################################################### def mueveVirtualServers(): inibloque=0 finbloque=0 bloque=[] lineas=varnishRLib.leeFichero(varnishRLib.config["nfConfApache"][0]) varnishRLib.log(" INFO -> Leyendo configuracion VirtualHost de Apache\n") for n in range(0,len(lineas)): linea=lineas[n] if re.match("<VirtualHost ((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(.+))\:\d{2,4}>", linea ): varnishRLib.log(" INFO -> Encontrado VirtualHost "+linea) varnishRLib.log(" INFO -> Moviedo Vhost a IP/puerto de apache\n") inibloque=n print "<br>Virtual Host encontrado: "+linea #Cogemos IP y puerto ini=linea.find(" ") fin=linea.find(":") IPvieja=linea[ini+1:fin] #IP de VHost Apache puertoviejo=linea[fin+1:len(linea)-2] #Leemos el puerto en el que esta if puertoviejo=="443": print "<br>Host SSL omitido" continue
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web ambos. De esta forma se consiguen realizar todas las tareas necesarias tanto por una lado para preparar el sistema instalando Varnish y el módulo de Apache RPAF en el caso de que no lo estén previamente, como por otra parte aplicar a ambas herramientas las configuraciones que figuren en el fichero de configuración de nuestro módulo tal y como se ha explicado en las secciones donde tratábamos estos scripts analizando su contenido y funcionamiento. A la hora de acceder a la página HTML que genera este CGI, el administrador verá en la ventana una serie de sentencias informativas sobre las diferentes acciones que se estén ejecutando en segundo plano. A la finalización de las cuales, como es habitual en nuestro módulo, se muestra un hiperenlace que nos lleva a la página principal del modulo si lo pulsamos. Hay que destacar que al final de la ejecución del código de nuestro fichero CGI, se procede a lanzar al sistema la orden de reiniciar el servicio Webmin mediante la instrucción “service webmin restart”. Debido a esto, la mayoría de las veces la ejecución es tan rápida que el navegador no es capaz de mostrar todas y cada una de las sentencias informativas que mencionábamos anteriormente, aunque sí se registran todas las acciones en el conocido fichero de log de nuestro módulo de integración. 48 Ilustración 23: Extracto de código del fichero applySettings.cgi print "<html><head><link rel='stylesheet' type='text/css' href='/unauthenticated/reset-fonts-grids-base.css'>" print "<link rel='stylesheet' type='text/css' href='/unauthenticated/virtual-server-style.css' />" print "<title>Servidor Varnish como Proxy inverso de Apache</title></head><body>" apacheConf.main() #lanzamos script instala Varnish proxy de apache VarnishApache.main() #lanzamos script configura VHost de Apache print "<br>Reiniciando VirtualMin(Webmin)" print "<br><br>" print "<a href='/varnishReverse/index.cgi'>Indice del Modulo</a>" print "</body></html>" sys.stdout.flush() varnishRLib.log(" INFO - Reiniciando WebMin\n") subprocess.call(["service","webmin","restart"])
5.10. editFile.cgi Este es el CGI cuya ejecución muestra al administrador un cuadro de texto en el que poder editar directamente el fichero que controla el comportamiento de la cache de Varnish, es decir, el fichero VCL del que se habla más adelante. Para acceder a la pantalla que genera el script, el administrador deberá pulsar en el icono de la derecha del todo de la ventana principal de nuestro módulo de Virtualmin. 49 Ilustración 24: Captura de parte de los mensajes informativos que proporciona el módulo al aplicar la integración. Ilustración 25: Extracto de código del fichero editFile.cgi que carga un fichero en pantalla. fichero=varnishRLib.config["nfDefaultVcl"][0] print "<form class='ui_form' action='editFileSave.cgi' method='post' enctype='multipart/form-data'>" print "<input class='ui_hidden' type='hidden' name='file' value='"+fichero+"'>" print "<textarea class='ui_textarea' name='data' rows='20' cols='80' style='width:100%'>" cont=varnishRLib.leeFichero(fichero) for linea in cont: linea=linea.replace("\n","") print linea #Cargamos las lineas del fichero en el cuadro de texto print "</textarea><br>" print "<table class='ui_form_end_buttons' ><tr>" print "<td><input class='ui_submit' type='submit' name='save' value='Salvar'>" print "</td>" print "</tr></table>"
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Al ejecutar este fichero, en el navegador de la persona que esté administrando el servidor aparecerá un cuadro de texto, más concretamente un objeto HTML textarea, tal y como puede verse en la imagen 26. El script se encarga de rellenar ese cuadro de texto con el fichero VCL que esté especificado en el atributo nfDefaultVcl de nuestro archivo de configuración del módulo. El código simplemente abre el fichero y lo recorre de forma secuencial, copiando cada línea del mismo dentro del elemento textarea. Al mismo tiempo, se le muestra al administrador un botón que lanza a ejecución el CGI editFIleSave, del cual hablaremos a continuación, pero cuyo trabajo a grandes rasgos consiste en guardar los cambios que se hayan hecho a través del cuadro de texto. Por último se muestra un enlace al índice del módulo, para permitir a la persona que esté navegando poder retornar a la pantalla principal sin utilizar los botones de su navegador web. 5.11. editFileSave.cgi Éste es el CGI que se lanza a ejecución cuando el administrador pulsa el botón para guardar los cambios efectuados en el fichero de Varnish VCL desde la ventana generada por el script editFile.cgi. 50 Ilustración 26: Captura de la ventana de nuestro módulo que permite editar el fichero VCL de Varnish.
En el código del fichero observamos que en primer lugar se comprueba que a través de la llamada que recibe el script se envíe una variable llamada file. En caso contrario se detiene la ejecución y no se hace nada. En caso de que, efectivamente, tengamos esa variable, cargamos su contenido en la variable form. Así, posteriormente, mediante el uso de las funciones de nuestra librería varnishRLib guardamos todo el contenido recibido en el fichero VCL que indique la entrada nfDefaultVCL de nuestro archivo de configuración. Como paso final, el código manda al sistema la orden de reiniciar el servicio Varnish para que los cambios tengan efectos inmediatos. Durante todo el proceso se muestran en el navegador sentencias informativas de las acciones que se llevan a cabo en segundo plano, guardando también registro de estas acciones en el fichero de log de nuestro módulo. 51 Ilustración 27: Extracto de código del fichero editFileSave.cgi. form = cgi.FieldStorage() #Se cargan los parametros if "file" not in form and "data" not in form : exit()#Si no hay fichero ni datos salimos else : print "Pragma: no-cache" print "Content-Type: text/html; Charset=UTF-8\n" sys.stdout.flush() sys.stderr.flush() sys.stderr = sys.stdout print "<html><head><link rel='stylesheet' type='text/css' href='/unauthenticated/reset-fonts-grids-base.css'>" print "<link rel='stylesheet' type='text/css' href='/unauthenticated/virtual-server-style.css' />" Ilustración 28: Captura de los mensajes de confirmación que genera el módulo al guardar los cambios en el fichero VCL.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Al final de la ventana que ve el administrador, como es habitual en el entorno de nuestro módulo, se muestra un enlace a la pantalla principal, es decir, a index.cgi. 5.12. module.info / install_check.pl Estos dos ficheros son de obligada inclusión a la hora de desarrollar cualquier módulo para el panel Webmin y ayudan al propio panel a integrar el módulo y gestionarlo. En primer lugar, el fichero module.info contiene los metadatos referentes a nuestro módulo. Se compone de cuatro atributos seguidos del símbolo “=” y del valor que necesitemos darles para nuestro módulo. En nuestro caso los atributos y sus valores son: •desc=Vanrish proxy inverso Este es el nombre identificativo de nuestro módulo, es decir, con qué nombre va a aparecer en la lista dinámica de módulos de Webmin. •os_support=*-linux Esta entrada indica los sistemas operativos para los que nuestro módulo es compatible, por ello soporta múltiples valores separados por comas. En nuestro caso el sistema operativo para el que ofrecemos compatibilidad es cualquier distribución Linux. •version=0.9 Como se puede deducir por en nombre, en esta entrada del fichero indicamos el número de versión de nuestro módulo. En nuestro caso hemos optado por ofrecer una versión previa a la 1.0, es decir, una versión beta, pues aún con todo el desarrollo correcto, sería recomendable darle varios meses de rodaje para pulir posibles errores que se hayan escapado y añadir funcionalidades en las que no hayamos caído. •category=servers Esta línea del archivo sirve para indicar la sección de los menús desde la cual se podrá acceder a nuestro módulo. En nuestro caso, como el objetivo es gestionar servidores virtuales hemos decidido incluirla en la sección de servidores, donde puede encontrarse también el módulo de Apache. Por último, según la documentación de Webmin, el fichero install_check.pl es necesario para que el propio panel pueda verificar que el módulo se ha instalado correctamente, para lo cuál deberá devolver el valor 0 al ejecutarse. Así que simplemente hemos incluido la instrucción return 0. 52
5.13. Fichero varnish Este archivo, que durante la instalación del módulo se copia al directorio de Varnish en /etc/sysconfig/varnish/, tiene definidas las diferentes variables de entorno que utiliza el servicio del proxy para arrancar de la manera deseada. Puede verse un estracto del fichero en la imagen 29. Los valores de sus entradas vienen definidos por defecto para una configuración estándar. Pero recordemos que la mayoría de esos parámetros son configurables a través del formulario de configuración de nuestro módulo. Ya se han estudiado la inmensa mayoría de entradas que contiene previamente cuando explicamos nuestro fichero de configuración config.file. 5.14. Generación e instalación del módulo Un fichero de instalación de cualquier módulo de Webmin es un directorio comprimido en formato .tar al que le cambiamos la extensión por .wbm. Con esto en mente, en nuestro caso hemos utilizado el programa 7zip [20] para comprimir el esquema de directorios y ficheros que hemos mencionado en todos los puntos anteriores y del cual se puede ver un esquema en la siguiente ilustración. De esta forma conseguimos generar con éxito el archivo que necesita el panel de control para instalar correctamente nuestro módulo en el sistema. En nuestro caso generamos el fichero varnishReverse.wbm. 53 Ilustración 29: Extracto del código del fichero de configuración del servicio Varnish VARNISH_STORAGE_SIZE=300M #Backend storage specification VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" #Default TTL used when the backend does not specify one VARNISH_TTL=120 DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \ -f ${VARNISH_VCL_CONF} \ -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ -t ${VARNISH_TTL} \ -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},$ {VARNISH_THREAD_TIMEOUT} \ -u varnish -g varnish \ -S ${VARNISH_SECRET_FILE} \ -s ${VARNISH_STORAGE}"
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Posteriormente hemos procedido a instalar nuestro desarrollo en la máquina virtual CentOS, que recordemos, ya tiene instalado un panel Virtualmin y un servidor web Apache. Los pasos para realizar la instalación del módulo se ilustran a continuación. En primer lugar debemos acceder al panel de control Virtualmin desde el navegador de la máquina donde tenemos el archivo .wbm y autenticarnos como un usuario válido para realizar las tareas de administración. Para ello ingresaremos en un navegador web la página https://192.168.0.103:10000 (en el caso de que el sistema CentOS tenga una dirección IP diferente será esa la que debamos ingresar). Entonces nos aparecerá la ventana donde podremos loguearnos con nuestras credenciales, tal y como puede verse en la imagen 7. El paso siguiente será navegar hasta la sección de Webmin desde la que se gestiona la configuración del propio panel. Para ello haremos clic en el botón de acceso a Webmin que se encontrará en la esquina superior izquierda de la pantalla, y a continuación desplegaremos el submenú lateral llamado “Webmin”, llegando a la pantalla que puede verse en la imagen 31. 54 Ilustración 30: Esquema en árbol del directorio de ficheros y carpetas que se comprime para generar el fichero .wbm.
Una vez ahí, como administradores deberemos acceder a la sección “Configuración de Webmin” y nos aparecerá una pantalla con todos los iconos que dan acceso a las diferentes opciones de configuración del panel, tal y como muestra la siguiente imagen. El botón que nos interesa para instalar nuestro módulo es el icono llamado “Módulos de Webmin”, pulsaremos en él y accederemos a la pestaña desde la que se añaden nuevas extensiones a nuestro panel. En esta pestaña aparecen numerosas opciones a través de las cuales podríamos instalar nuestro módulo, pero en nuestro caso concreto, la más cómoda es la alternativa “Desde archivo a cargar”. Así pues, activamos la opción y hacemos clic en el botón “Examinar...”. Se nos desplegará un navegador de archivos y seleccionaremos nuestro módulo que, recordemos, empaquetamos anteriormente como “varnishReverse.wbm”. A continuación deberemos pulsar sobre el botón “Instalar módulo”. 55 Ilustración 31: Captura de la página principal de Webmin con el primer menú lateral desplegado. Ilustración 32: Captura de el menú de configuración principal del panel Webmin.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Cuando la instalación se complete, el panel nos mostrará un mensaje confirmándonos que el proceso ha concluido con éxito. En ese mismo mensaje tendremos un enlace que podremos pinchar para ir a la página principal de nuestro módulo. A partir de entonces podremos encontrar nuestra extensión para Varnish en el panel de Webmin, dentro del menú desplegable de “Servidores”, pues esa es la sección que indicamos dentro del fichero module.info tal y como veíamos unas páginas atrás (y como puede verse en la ilustración 35). Y así es como instalamos nuestro módulo en el panel de control Virtualmin. 56 Ilustración 33: Captura del desplegable desde el cual subimos nuestro módulo en formato .wbm Ilustración 34: Mensaje de confiramción de Webmin tras instalar con éxito nuestro módulo.
57 Ilustración 35: Localización del acceso a nuestro módulo dentro del panel de control webmin.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web •Decidir las políticas de cacheo de objetos, por ejemplo no almacenar en cache peticiones POST o solo almacenar ciertas URLs. •Ejecutar reglas de reescritura de algunos datos de cliente utilizados por algunas aplicaciones web específicas. •Añadir barreras de seguridad para evitar ataques. Todas estas situaciones han sido tratadas e implementadas más adelante, recordando que nuestro desarrolla busca ser una solución general intentando abarcar la máxima funcionalidad posible para el máximo numero de servidores posibles sin intentar resolver situaciones muy concretas que puedan responder a necesidades de ciertos servidores y sus páginas. Volviendo a vcl_recv, una vez realizadas las acciones anteriores, es posible tomar tres caminos diferentes. En primer lugar podemos hacer un pass, que supone ejecutar el resto de la lógica de procesamiento pero sin buscar coincidencias en la cache y sin tratar de almacenar la respuesta generada. Es decir, se pedirá al backend la respuesta y se le enviará al cliente, sin más. Otra opción, llegados al final de vcl_recv, es hacer un pipe. Ésto no es ni más ni menos que crear una conexión directa entre nuestro servidor backend y el cliente. Toda la transmisión a través de la pipe será interpretada por Varnish como simples bytes que retransmitirá a un lado o a otro sin intentar comprenderlos. Por este motivo, cualquier petición que se genere a consecuencia del pipe mientras el tiempo keep-alive connection siga activo pasará también por el proxy con la misma técnica. La opción que más nos interesa es buscar (o hacer un lookup) de la petición en la cache, respondiendo con la respuesta correspondiente en caso de que se encontrara o almacenando la respuesta generada por el backend en el caso de que no se encontrara en la cache. Por último, en vcl_recv podemos generar una respuesta de error desde Varnish, indicando una redirección o cualquier cosa que nos interese. Ésto se hace con error. 64
6.3.1 Código por defecto Procedemos a ilustrar el código de la función vcl_recv( ) que incluimos por defecto al aplicar la integración con nuestro módulo. 65 Ilustración 38: Código que incluimos por defecto en la función vcl:recv( ). #VCL configuracion sub vcl_recv { #Anñadimos a la peticion la IP del cliente para estadisticas if (req.restarts == 0) { if (req.http.x-forwarded-for) { set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; } else { set req.http.X-Forwarded-For = client.ip; } } if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT" && req.request != "POST" && req.request != "TRACE" && req.request != "OPTIONS" && req.request != "DELETE") { /* Peticion no exitente en RFC2616*/ return (pipe); } if (req.request != "GET" && req.request != "HEAD") { /*Solo cacheamos GET y HEAD*/ return (pass); } if (req.http.Authorization || req.http.Cookie) { /*Si hay cookie o se negocia una conexion no cacheamos*/ return (pass); } #Controlamos que el servidor esta arriba if (req.backend.healthy) { set req.grace = 30s; } else { /*Si Apache down, grace y aguantamos los obj 1h*/ set req.grace = 1h; } return (lookup); }
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web La primera parte del código es la que hace uso del mencionado módulo RPAF de Apache. Lo que hace es añadir en una cabecera de la petición que va a enviar al servidor web, la dirección IP del cliente que originó la petición en primera instancia. Gracias a esto, como hemos comentado anteriormente, las estadísticas de Apache son más completas y se registran los accesos con la IP que deben registrarse, y no con la del servicio Varnish, que es lo que sucedería en caso de que no aplicáramos ésta técnica. En segundo lugar, nuestro código comprueba que la petición entrante se una que cumpla con el estándar HTTP según el RFC2616. En caso contrario, se entiende que Varnish no va a ser capaz de tratar la petición, por lo que crea una conexión directa entre cliente y servidor, es decir, se hace un pipe. El código que sigue se encarga de intentar mandar a cache tan solo las peticiones HEAD y GET, pues no resulta de interés ni utilidad por lo general intentar guardar en cache otros tipos de peticiones como pueda ser POST. También discrimina las peticiones que tienen una cookie o que llevan la cabecera de negocio de conexión authorization. Si la petición cumple cualquiera de estas condiciones, se derivará como un pass, es decir, no intentará recuperar la respuesta de la cache. Por último vemos dónde se realizan los health-checks que hemos definido en la sección anterior. Tal y como puede verse, en caso de que Varnish declare el servidor Apache caído, pondrá los objetos petición en modo grace durante una hora, es decir, se obviará el tiempo TTL y se mantendrán los objetos relacionados con sus peticiones durante sesenta minutos, dando tiempo al administrador a solucionar las incidencias técnicas. Como resulta evidente, este mecanismo deberá eliminarse en caso de que un sitio web no pueda servir contenido antiguo a los clientes. 6.4. vcl_fetch La función vcl_fetch es la equivalente a vcl_recv pero por parte del servidor web o backend. Mientras que en una podemos utilizar la diferente información proporcionada por el cliente para actuar en consecuencia con unas políticas de cache u otras, en vcl_fetch tenemos la diferencia de que el que nos proporciona información útil es el servidor web. En esta función se aconseja hacer las siguientes tareas: •Sobrescribir el tiempo que se mantiene en cache un objeto de una URL determinada. •Eliminar las cabeceras set-cookie que sean dispensables. •Crear un objeto hit_for_pass. Dentro de la función tenemos disponibles diferentes datos de la respuesta, de los cuales el más importante y usado es beresp.ttl. Esta variable asociada a un objeto respuesta del servidor indica a Varnish durante cuánto tiempo se mantendrá el objeto generado en la cache. Por defecto éste valor coincidirá con el valor que le hayamos asignado al servicio Varnish en el campo default_TTL. Para terminar la ejecución de esta función tenemos dos caminos diferentes. Por un lado podemos hacer un return(deliver), con lo cual Varnish enviará al cliente su respuesta y la guardará en cache sí es posible. Por otro lado, tenemos la opción de terminar con un return(hit_for_pass). Esta instrucción hará que Varnish almacene en cache un objeto de tipo homónimo hit_for_pass enlazado a la petición que lo generó. Es muy importante tener en cuenta 66
que el TTL del objeto hit_for_pass se aplica como a un objeto normal. De este modo, cualquier petición posterior que sea igual que la que generó éste objeto, sí entra a Varnish dentro del tiempo TTL del objeto, entrará en la función pass( ) de forma automática. Es decir, creando un hit_for_pass estaremos almacenando en cache la decisión de que esas peticiones hagan un pass durante un periodo de tiempo determinado. 6.4.1 Código por defecto A continuación ilustramos la función vcl_fetch( ) que incluimos por defecto en nuestro fichero VCL. La primera parte de código de nuestra función hace que en caso de que el servidor web Apache conteste una petición con una cabecera set-cookie marcaremos esa respuesta como hit_for_pass y la acción se recordará para todas las peticiones que generen la misma respuesta durante los próximos dos minutos. Es extremadamente extraño que se desee guardar en cache una respuesta con una cabecera de ese tipo. Por último, al final del código podemos ver como asignamos un valor de grace de una hora a todas las respuestas que se guarden en cache. Recordemos que este tiempo solo se tendrá en cuenta en cuanto se caiga el servidor Apache. Mientras eso no suceda, el valor del atributo TTL es el que manda. 6.5. vcl_hash En esta función se define la clave de dispersión que será usada para asociar un objeto en cache con la petición que le corresponde. En otras palabras, decide qué es único en una petición. Se ejecuta inmediatamente después de vcl_recv. 67 Ilustración 39: Código de la función vcl_fetch( ) que utilizamos por defecto. sub vcl_fetch { if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") { /* Marcamos como HitForPass durante 2 min*/ set beresp.ttl = 120 s; return (hit_for_pass); } /*Activamos modo grace*/ set beresp.grace = 1h; return (deliver); }
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Un posible uso de esta sección podría ser añadir un nombre de usuario concreto para un objeto de la cache que sea de uso específico para ese usuario, sin embargo, es una práctica arriesgada pues de esta forma dispersaríamos mucho el contenido de la cache, perdiendo eficacia y eficiencia, ya que el objetivo es almacenar en cache los objetos que reciban más peticiones por parte de los clientes en general, no de uno unicamente. 6.5.1 Código por defecto Detallamos el código que utilizamos para identificar un objeto respuesta con su petición en la cache. El sencillo código de nuestra función de dispersión de Varnish nos proporciona una solución eficaz para la mayoría de sistemas. Las peticiones se diferencian unas de otras según la URL y la cabecera host (o la dirección IP de destino en caso de que la petición no tenga dicha cabecera). Gracias a esto obtenemos un correcto funcionamiento de la cache, evitando la redundancia de objetos. 6.6. vcl_hit El código de esta sección se ejecuta en cuanto un objeto se localiza con éxito en la cache de Varnish. En esta función se puede cambiar el atributo TTL de un objeto, por ejemplo ampliar el TTL en el caso de que nuestro servidor Apache esté caído. También es la función desde la que se pueden realizar purgas de los objetos, ésto es eliminarlos de la cache. 68 Ilustración 40: Código de la función vcl_hash( ) que incluimos por defecto en el módulo. sub vcl_hash { #Utilizamos la ULR de la peticion hash_data(req.url); #Y la cabecera HOST si existe if (req.http.host) { hash_data(req.http.host); } else { #O la IP del servidor hash_data(server.ip); } return (hash); }
6.6.1 Código por defecto En el caso de que el objeto se encuentre en la cache, nuestro código simplemente activará la función que se encarga de entregarlo al cliente. 6.7. vcl_miss Se ejecuta después de buscar un objeto en la cache y no encontrarlo. La principal función que se le da a esta sección es realizar la purga de los objetos de la cache. En versiones de Varnish anteriores, también se utilizaba esta función para modificar las cabeceras de las peticiones que vamos a enviar al servidor web, pero actualmente esas acciones se realizan en vcl_recv. 6.7.1 Código por defecto Al igual que ocurre con la función hit( ), el código de vcl_miss( ) es muy sencillo pero funcional. Cuando un objeto no se encuentra en cache, se activa la función que se encarga de pedirlo al servidor web Apache. 6.8. vcl_pass Esta función podemos englobarla en el mismo grupo que vcl_hit y vcl_miss. Su código se ejecuta después de que una búsqueda en cache o la función vcl_recv determinan que el objeto no se encuentra en cache, pero que tampoco es posible cachearlo (por ejemplo si tiene cookies de usuario). La utilidad de esta función es limitada, pero típicamente se puede utilizar para controlar aspectos que hayas implementado tanto en vcl_hit como en vcl_miss. El uso más extendido para esta función es evitar que una petición de purga de la cache llegue a nuestro servidor Apache. 69 Ilustración 41: Código por defecto que incluimos en la función vcl_hit( ) sub vcl_hit { return (deliver); } Ilustración 42: Código por defecto que incluimos en la función vcl_miss( ). sub vcl_miss { return (fetch); }
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 6.8.1 Código por defecto Tal y como sucede con las ultimas dos funciones anteriores, el código de esta función es básico y funcional. Lanza la petición al servidor como pass en el caso de que en vcl_recv( ) se devuelva un pass o al buscar el objeto correspondiente en la cache, éste esté marcado como hit_for_pass. 6.9. vcl_deliver La función de la que tratamos ahora es el punto de salida de la lógica de ejecución del fichero VCL para todas las funciones menos para vcl_pipe. Su utilidad es principalmente testear y debuguear, pues permite modificar directamente la respuesta que envía Varnish al cliente, independiente de sí ha salido de cache o del servidor web Apache. Aquí podemos eliminar cabeceras HTTP que no nos interesen, o añadir las que deseemos (que no habremos añadido antes porque no queremos que se almacenen en cache). Las principales variables que podemos modificar en esta función son las siguientes. •resp.http.* Conjunto de cabeceras que se van a enviar al cliente. Pueden añadirse o quitarse. •resp.status Código de estado de la respuesta HTTP (200, 404, 503, etc). •resp.response Mensaje de respuesta, normalmente asociado al código de la respuesta (“Ok”, “File not found”, “Service enavailable”, etc). •obj.hits Número de veces que se ha obtenido un objeto con éxito de la cache. Puede ser tratado como una cadena, por lo que no habrá que convertir ningún tipo de datos a otro para usarlo. •req.restarts Numero de reinicios que ha provocado una respuesta en la lógica VCL. 70 Ilustración 43: Código por defecto de la función vcl_pass( ). sub vcl_pass { return (pass); }
6.9.1 Código por defecto A continuación de ilustra y explica el código por defecto que hemos incluido en la función vcl_deliver( ). Nuestra función vcl_deliver( ) ayuda al administrador a probar la efectividad de la cache. Lo que hace es añadir en el objeto que se devuelve al cliente, una cabecera HTTP X-Cache que valdrá MISS en el caso de que el objeto no se haya recuperado de la cache, o HIT en el caso de que sí se haya respondido a la petición con el objeto de cache. Además, añadimos el número de veces que se ha conseguido un acierto en el objeto, antes de que sea retirado de memoria cuando acabe su TTL. 6.10. vcl_error Tal y como el nombre de la función indica, esta función se ejecuta cuando sucede un error a la hora de procesar una petición. Es posible generar una página HTML sintética desde el código de esta sección, por lo que Varnish no tiene por qué recuperar esa página de error que se le va a mostrar al usuario de ningún servidor web concreto. 6.10.1 Código por defecto El código que incluimos en la función de error de Varnish es el mismo que ofrecen en su documentación como solución estándar. La decisión responde a que al ser un mensaje de error, es muy probable que un administrador desee personalizarlo y adaptarlo a su sitio web para mejorar lo máximo posible la experiencia de los usuarios de su web en el caso de que se produzca una situación de fallo. 71 Ilustración 44: Código por defecto de la función vcl_deliver( ). sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "HIT "+obj.hits; } else { set resp.http.X-Cache = "MISS"; } return (deliver); }
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Tal y como puede apreciarse, se trata de una página HTML sintética, es decir, que se genera al vuelo e incluye cierta información referente al objeto que ha causado el error. 72 Ilustración 45: Código por defecto de la función vcl_error( ). sub vcl_error { set obj.http.Content-Type = "text/html; charset=utf-8"; set obj.http.Retry-After = "5"; 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); }
7. Pruebas de funcionamiento 7.1. Pruebas de funcionamiento del módulo Para poder comenzar a probar nuestro módulo, debemos preparar el sistema para crear un entorno donde podamos observar con certeza si el módulo realiza correctamente sus tareas o no. Por este motivo procedemos a arrancar nuestra máquina virtual y nos conectaremos al panel Webmin que ya trae preinstalado. El primer paso que hemos hecho ha sido poner el servidor web Apache a esperar peticiones en la dirección IP de nuestra máquina virtual y en dos puertos, en el 80 y en el 443. Para conseguirlo podemos proceder de dos formas diferentes. Una de ellas es editar a mano el fichero de Apache donde de se especifica en qué direcciones y puerto va a escuchar peticiones. Y la otra forma es a través de la interfaz gráfica que nos ofrece Webmin para configurar Apache. Independientemente del método que decidamos utilizar, los resultados serán los mismos, pues lo que hace la interfaz gráfica a nivel interno, es precisamente modificar el fichero localizado en /etc/httpd/conf/, por eso vamos a ilustrar cómo hacerlo desde el entorno gráfico para posteriormente ver los cambios en el fichero. Sabiendo ésto, vamos al menú desplegable de Webmin llamado “Servidores” y hacemos clic en “Servidor web Apache”. Una vez ahí, pinchamos sobre la pestaña “Global configuration”, en la que nos aparecerán todas las opciones de Apache. Aquí pulsaremos sobre el icono de “Redes y direcciones” para acceder al menú desde el cual editar las direcciones en las que se encuentra Apache, tal y como se ve en la figura 46. Una vez aquí, en la sección del formulario donde dice “Escuchar en direcciones y puertos”, introduciremos la dirección IP de nuestra máquina y en el cuadro de puerto pondremos el puerto 80. Haremos lo mismo en el recuadro inferior, solo que esta vez pondremos el puerto 443. Por último haremos clic en el botón inferior para salvar los datos de configuración. 73 Ilustración 46: Captura del formulario de configuración de "Redes y direcciones" de Apache.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Como podemos observar, el objeto se encuentra en cache. Es momento de desconectar Apache: Ahora, con Apache desconectado, esperamos más de 120 segundos, que es el tiempo TTL de los objetos en cache que hemos puesto por defecto. Una vez pase ese tiempo, lanzamos otra petición equivalente al host “prueba.com”. Fijándonos en la imagen 57, podemos ver como se ha comportado el proxy inverso ante la caída del servidor web. Nos ha contestado a la petición con el objeto que tenía en cache, pero si nos fijamos en la cabecera “Age: 135” vemos que ese valor es superior al máximo de 120 establecido por defecto. Esto sucede porque al desconectar Apache, Varnish pone los objetos de la cache en estado grace, el cual hemos especificado que aguante durante una hora sirviendo el contenido cacheado. Cuando un objeto está en estado grace, su atributo TTL es omitido, y se mantiene en cache tanto tiempo como hayamos indicado al atributo obj.grace. Sí por el contrario, realizamos una petición HTTP al host “prueba.es”, cuyo objeto de respuesta no se encontraba en la cache antes de tumbar Apache, vemos como efectivamente Varnish nos responde con un error, pues no es capaz de servirnos el objeto solicitado ni desde la cache ni (evidentemente) desde el servidor web desconectado . 80 Ilustración 56: Orden de parada al servicio de Apache. Ilustración 57: Lanzamiento de la segunda petición al host "prueba.com" fuera del tiempo TTL establecido.
Como hemos podido comprobar con las pruebas realizadas, tanto nuestro módulo de integración, como la configuración VCL que incluimos por defecto funciona correctamente. 81 Ilustración 58: Respuesta de error que nos devuelve Varnish al no poder satisfacer nuestra petición por ningún medio.
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 82
8. Conclusión El desarrollo de este proyecto nos ha enseñado cómo a la vez que la tecnología evoluciona, van apareciendo nuevas necesidades por cubrir. Es parte de nuestra formación como ingenieros el descubrir, abordar y aprovechar esas necesidades de la forma más eficiente y eficaz posible. He aprendido cómo desarrollar un módulo para el panel de control Virtualmin. Que además, es capaz de añadir nuevas herramientas al sistema y configurarlas para que trabajen en armonía con todos los demás componentes. Mejorando las prestaciones y servicios de sistemas ampliamente utilizados en el sector. Al mismo tiempo, hemos tenido que aprender a desarrollar una solución lo más genérica posible, teniendo que decidir donde poner el límite en ciertas configuraciones, para no reducir el número de potenciales beneficiados de nuestro desarrollo. A nivel puramente formativo, he tenido que aprender un nuevo lenguaje de programación, Python, que nunca había utilizado antes en todos los años de formación académica. También he conseguido sentirme cómodo utilizando la herramienta Varnish Cache, de la que nunca antes había oído hablar. Y en general, he aprendido las bases del uso de cualquier proxy inverso y he mejorado mucho mis habilidades de trabajo con servidores web. Al final hemos conseguido cumplir el objetivo, adquiriendo nuevos conocimientos y mejorando los que ya teníamos por el camino. La satisfacción recibida por el trabajo bien realizado nos anima a seguir afrontando retos, sin importar de qué magnitud sean, porque gracias a ello creceremos como ingenieros y como personas. 8.1. Trabajo futuro Pese a haber cumplido el objetivo del proyecto, la naturaleza de nuestro desarrollo hace que éste tenga innumerables posibilidades de ampliación y mejora. Desde añadir más funcionalidades, hasta ampliar la compatibilidad con más entornos. Una posible vía de mejora sería que el módulo leyese la configuración y arquitectura del sistema para ajustar el servicio Varnish automáticamente lo máximo posible, sin que el administrador tenga que tocar nada. Esto nos permitiría omitir muchos valores por defecto iniciales. Otra sugerencia para mejorar nuestro desarrollo puede ser añadir a la interfaz de nuestro módulo una nueva ventana en la que el administrador pueda ver el estado del servicio Varnish Cache en tiempo real, así como estadísticas o avisos importantes de errores. Una última posibilidad de ampliación que se estuvo barajando es la de incluir un amplio abanico de ficheros VCL por defecto, cada uno respondiendo a las necesidades de diferentes sitios web tipo. De esta forma, el administrador tan solo tendría que elegir qué tipo de sitio web está alojando en su servidor para conseguir una configuración por defecto algo más adaptada a sus necesidades. 83
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 84
9. Referencias [1] Internet Live Stats. Total number of websites. [última consulta 20/05/2015] http://www.internetlivestats.com/total-number-of-websites/ [2] Netcraft Ltd. Web Server Survey. [última consulta 20/05/2015] http://news.netcraft.com/archives/category/web-server-survey/ [3] CentOS.org. Wiki CentOS. [última consulta 15/06/2015] http://wiki.centos.org/ [4] Python Software Foundation. [última consulta 16/06/2015] https://www.python.org/ [5] Python Software Foundation. Wiki Python. [última consulta 16/06/2015] https://wiki.python.org/ [6] Apache Software Foundation. Wiki Apache. [última consulta 16/06/2015] http://wiki.apache.org/general/ [7] Apache Software Foundation. [última consulta 16/06/2015] http://httpd.apache.org [8] Kurose, James F. y Ross, Keith w (2010). Redes de computadoras. Un enfoque descendente (5a ed). Madrid: Pearson. [última consulta 1/07/2015] [9] Webmin. Webmin documentation. [última consulta 16/06/2015] http://doxfer.webmin.com/Webmin/Introduction/ [10] Webmin. Webmin modules. [última consulta 16/06/2015] http://doxfer.webmin.com/Webmin/Webmin_Modules/ [11] Virtualmin Inc. Specs Comparation. [última consulta 20/06/2015] https://www.virtualmin.com/compare.html [12] Varnish Software. Wiki Varnish. [última consulta 5/07/2015] https://www.varnish-cache.org/trac [13] Varnish Software. Main. [última consulta 20/06/2015] https://www.varnish-cache.org [14] Varnish Software. Working with virtual hosts. [última consulta 26/06/2015] https://www.varnish-software.com/blog/getting-virtual-hosts-right-varnish-cache [15] StackExchange. Programers section. [última consulta 20/06/2015] http://programmers.stackexchange.com/questions/83818/what-does-proxy-to-mean [16] CCM.net. Diferencias entre porxy y proxy inverso. [última consulta 16/06/2015] 85
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web http://es.ccm.net/contents/297-servidores-proxy-y-servidores-de-proxy-inversos [17] Apache Software Foundation. Name-based Virtual hosting. [última consulta 20/06/2015] http://httpd.apache.org/docs/current/vhosts/name-based.html [18] Apache Software Foundation. VirtualHost Examples. [última consulta 1/07/2015] http://httpd.apache.org/docs/2.2/vhosts/examples.html [19] Apache Sotware Foundation. Module Index. [última consulta 1/07/2015] http://httpd.apache.org/docs/2.2/mod/ [20] Igor Pavlov. 7-zip main site. [última consulta 21/06/2015] www.7-zip.org/ [21] Nate Haug. Configuring Varnish for high avaliability. [última consulta 30/06/2015] https://www.lullabot.com/articles/configuring-varnish-for-highavailability-withmultiple-web-servers [22] Varnish Software. Oficial Varnish 3.0 Docs. [última consulta 4/07/2015] https://www.varnish-cache.org/docs/3.0/index.html [23] Kwalsh. Online Python Interpreter. [última consulta 25/06/2015] http://mathcs.holycross.edu/~kwalsh/python/ [24] Blackhold. Configurando Apache para alto rendimiento. [última consulta 30/06/2015] http://blackhold.nusepas.com/2010/05/configurando-apache-para-la-guerra-altorendimiento/ [25] Varnish Software. VCL Examples. [última consulta 3/07/2015] https://www.varnish-cache.org/trac/wiki/VCLExamples [26] Varnish Software. 1O common Vanrish mistakes. [última consulta 3/07/2015] https://www.varnish-software.com/blog/10-varnish-cache-mistakes-and-howavoid-them [27] Stackoverflow. Varnish Hit for Pass meaning. [última consulta 26/06/2015] http://stackoverflow.com/questions/12691489/varnish-hit-for-pass-means [28] Ned Productions Ltd. A perfect configured Varnish VCL. [última consulta 4/07/2015] http://www.nedproductions.biz/wiki/a-perfected-varnish-reverse-caching-proxyvcl-script [29] Varnish Software. Why no SSL? [última consulta 21/06/2015] https://www.varnish-cache.org/docs/3.0/phk/ssl.html [30] BuiltWith Pty Ltd. Web server usage statistics. [última consulta 2/07/2015] http://trends.builtwith.com/web-server 86
[31] Virtualmin Inc. Open Source Web Hosting and Cloud Control Panels [última consulta 4/07/2015] http://www.virtualmin.com/ [32] Wessels Duane (2001). Web caching. O'Reilly [última consulta 5/07/2015] [33] Varnish Software. The Varnish Book. [última consulta 5/07/2015] 87
Integración de un proxy inverso Varnish Cache con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 88
89