scieee AI-readable full text Open interactive document viewer

Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web

Molina Coronado, Borja

Abstract

[ES] 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, open source, 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 NGINX en su modialidad de proxy inverso de forma que se pueda gestionar de forma transparente desde el panel de control Virtualmin. El desarrollo se realizará en máquinas virtuales para tener mayor flexibilidad. Se realizarán inicialmente configuraciones manuales, se afinarán los parámetros de configuración y posteriormente se diseñarán scripts de automatización. Se utilizará el S.O. Linux con distribución CENTOS.

Full text

Escola Tècnica Superior d’Enginyeria Informàtica Universitat Politècnica de València Integración de un proxy inverso NGINX 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: Borja Molina Coronado 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 web, open source, 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 NGINX en su modalidad de proxy inverso, de manera que se pueda gestionar de forma transparente desde el panel de control Virtualmin. El desarrollo se ha realizado en una máquina virtual para tener mayor flexibilidad. Inicialmente se han analizado las herramientas y diseñado los scripts de automatización que realizan todas las configuraciones. Todo ello, bajo el S.O. Linux con distribución CentOS. Palabras clave: NGINX, Apache, servidor virtual, Python, Virtualmin, WebMin, integración, proxy inverso, Linux, CENTOS. Abstract The use of a reverse proxy is a technique that allows you to improve the performance and decrease the servers load while the compatibility with the most popular web servers like Apache is kept. Virtualmin GPL is an open source control panel and hosting manager that allows you to create and configure automatically all resources associated with an Apache based hosting web. The purpose of this project is to install this software on a server and integrate it with NGINX in reverse proxy mode, so it can be managed in a transparent way from Virtualmin. The development has been made on a virtual machine for greater flexibility. Initially the tools have been analyzed and then the automatization scripts that make all the configurations have been designed. All of this was done using CentOS Linux Operating System distribution. Keywords : NGINX, Apache, virtual server, Python, Virtualmin, WebMin, integration, reverse proxy, Linux, CENTOS. 3 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 4 Tabla de contenidos 1.Introducción...................................................................7 1.1.Objeto.............................................................................................7 2.Contexto tecnológico......................................................9 2.1.VirtualMin......................................................................................9 2.2.NGINX..........................................................................................10 2.3.Apache..........................................................................................11 2.4.CentOS.........................................................................................12 2.5.Python..........................................................................................13 3.Descripción del problema............................................15 3.1.Esquema inicial del servidor.......................................................15 3.2.Esquema con proxy inverso.........................................................16 3.3.Esquema objetivo.........................................................................17 4.Implementación...........................................................19 4.1.Análisis de VirtualMin.................................................................19 4.2.Análisis de Apache.......................................................................21 4.3.Desarrollo....................................................................................22 4.3.1conf.file....................................................................................................................................23 4.3.2Libreria nginxReverselib.py....................................................................................................24 4.3.3Script ApaConf.py..................................................................................................................27 4.3.4Script Ap2Nginx.py................................................................................................................31 4.3.5Configuración de Virtual Servers en NGINX.........................................................................33 4.3.6Módulo para Webmin..............................................................................................................44 5.Pruebas........................................................................53 5.1.Sistema proxy inverso..................................................................53 5.2.Compresión de recursos..............................................................57 5.3.Cache NGINX...............................................................................58 5 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 6.Conclusiones................................................................61 6.1.Trabajo futuro..............................................................................61 7.Referencias..................................................................63 Anexos.............................................................................67 Anexo 1: Análisis estadístico.............................................................67 Clase Main.java...............................................................................................................................68 Clase DescargaWeb.java.................................................................................................................71 Clase TCPCon.java.........................................................................................................................73 Clase Peticion.java...........................................................................................................................75 Anexo 2: Análisis compresion GZIP...................................................77 Anexo 3. Generación de clave RSA y certificado autofirmado..........78 6 1. Introducción Hoy en día, el campo de las tecnologías de la información (IT por sus siglas en inglés) pone de manifiesto su importancia en el ámbito de los negocios, facilitando aspectos tales como: ganar visibilidad en el mercado, mejorar la eficiencia y proporcionar soluciones tecnológicas en base a las necesidades especificas de cada uno de ellos. Para cubrir algunas de estas necesidades han surgido en los últimos años distintas alternativas a las que ya se encontraban implantadas. Este auge de soluciones tecnológicas ha provocado que estas herramientas ya arraigadas tengan que trabajar en armonía con las nuevas aplicaciones que se han venido desarrollando a lo largo del tiempo. Además, se han ido implantando de forma paralela paneles software como VirtualMin —a un nivel más alto— facilitando la configuración y automatizando muchas de las tareas necesarias para desplegar dichas soluciones en los centros de datos. Este es uno de los motivos por los que la integración de aplicaciones software que utilizan tecnologías distintas se ha convertido en una de las responsabilidades mas destacadas dentro del campo de la informática e Internet. Esa torre de babel de tecnologías y protocolos de transmisión de datos, que llamamos Internet, donde la lengua que mayoritariamente se habla desde 1990 es el protocolo de transferencia de hipertexto (HTTP), desarrollado por el consorcio World Wide Web (W3C de sus siglas en inglés) y estandarizado por la Internet Engineering Task Force (IETF), es el que se utiliza en la web siguiendo un modelo de arquitectura cliente-servidor, en el que el programa servidor es quien recibe las peticiones de los usuarios, que serán los que den inicio a la conexión. Puesto que cada cliente puede abrir una o varias conexiones sobre el mismo servidor para recibir la información solicitada, uno de los grandes inconvenientes de esta arquitectura es la centralización de la información. La utilización de un proxy HTTP inverso es una técnica transparente para los clientes que realicen peticiones al servicio, proporcionando mejoras en el rendimiento y reducción en la carga de los servidores a la vez que se mantiene compatibilidad con las aplicaciones de servidor web más extendidas, como por ejemplo Apache. Esta es una de las principales razones por las que este tipo de despliegues comienza a tomar un papel importante dentro de las arquitecturas de red de las empresas de servicios de Internet, que comienzan a ver negocio en las posibilidades que ofrece, comercializando soluciones seguras, distribuidas y eficientes; aunque, pueden llegar a ser complejas de gestionar. 1.1. Objeto Debido a la expansión dentro del campo de las tecnologías de la información que esta experimentando el servidor NGINX, aumenta a su vez la necesidad de proporcionar herramientas que faciliten el manejo y la gestión de este producto. Gracias a esta fama que el servidor ha alcanzado —sobretodo en su modalidad como proxy inverso—, y debido a la complejidad de integración con Apache y la ausencia de soluciones desarrolladas —ya que no existen módulos que cubran estas tareas para los paneles de gestión opensource como son Webmin o VirtualMin—, 7 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web surge la necesidad de implementar una serie de herramientas que cumplan con este cometido, evitando al administrador la laboriosidad de realizar a mano todas y cada una de la operaciones requeridas. La finalidad de este proyecto es integrar NGINX de forma que trabaje como servidor proxy inverso conjuntamente con Apache, y más concretamente con los distintos servidores virtuales gestionados desde un panel de control VirtualMin. Para ello, se desarrollará un módulo con una interfaz intuitiva y que será capaz de realizar todas las tareas necesarias para desplegar dicha configuración en el servidor sin interferir con los distintos servicios que pueda haber en funcionamiento en el sistema, proporcionando transparencia y agilidad en su gestión. El desarrollo se realizará usando una maquina virtual, esto es, una aplicación en un sistema informático que emula un ordenador físico, proporcionando agilidad y aislamiento al desarrollo. Este emulador dispone de una instalación del sistema operativo de código abierto Linux CentOS en su versión 6.6. Este sistema operativo, además de las herramientas y tecnologías utilizadas, serán tratados con mas detalle en el punto 2, donde se explica el contexto tecnológico del presente trabajo para facilitar al lector su comprensión. Además se detalla el procedimiento llevado a cabo para la creación del módulo. Desde los scripts de automatización de las tareas habituales de instalación del servidor NGINX y las herramientas necesarias para que funcione junto con Apache, hasta la instalación del módulo creado para el panel de control, pasando por las configuraciones necesarias para que ambos servicios trabajen en sinfonía. 8 2. Contexto tecnológico 2.1. VirtualMin Basado en el panel web de código abierto para administración de sistemas Webmin, Virtualmin ha conseguido posicionarse como una alternativa libre y fiable a paneles de control de pago como cPanel o Plesk para la gestión de múltiples servidores web Apache. Existen dos modalidades de la aplicación: una gratuita y otra comercial, siendo la misma herramienta pero con soporte ofrecido por la empresa VirtualMin LLC. Concebido para facilitar la gestión de tareas de hosting, centralizando en una pagina web con una interfaz gráfica de usuario (GUI por sus siglas en Inglés) amigable la administración de todos los sitios web alojados por un servidor —también llamados Virtual Servers—. Un ejemplo de su interfaz puede observarse en la figura 1, en la que se muestra la pantalla de configuración de un servidor virtual de Apache. Como se puede ver en la imagen, proporciona métodos sencillos para la gestión de servidores virtuales dentro de una misma máquina mediante la visualización de menús y formularios en los que se pueden indicar los distintos ajustes, encargándose por sí mismo de forma transparente para el administrador, de todas las tareas necesarias para su creación y configuración. 9 Figura 1 – WebMin GUI para configuración del Vserver prueba.com Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web administración remota. En esta implementación, es el servidor quien se encarga directamente de servir todas las peticiones HTTP que le llegan desde internet con destino a su IP. 3.2. Esquema con proxy inverso. Una vez conocemos la configuración típica de un servidor web como la que disponemos para el desarrollo, es necesario explicar de qué se compone su variante con proxy inverso. Pero para ello, se hace necesario explicar cómo funcionan este tipo de servidores. Un proxy es un elemento intermedio entre los clientes y el servidor que actúa como servidor para el cliente —la dirección destino en la cabecera IP será la del proxy, y la de origen, la del cliente original—; esto es, como destino de todas las peticiones que el cliente envía hacia el servidor web, y como cliente para el servidor web, es decir, como origen de todas las peticiones que éste recibe —la dirección origen en la cabecera IP es la del proxy y la de destino la del servidor web, en nuestro caso Apache—, siendo este proceso totalmente transparente para los usuarios [31][44]. Además, este tipo de servicios poseen la capacidad de almacenar objetos en memoria, lo que evita realizar peticiones para esos recursos al servidor. Este tipo de diseños hacen las funciones de cache web, proporcionando mejoras en el rendimiento aligerando la carga de un servidor web debido al gran número de peticiones que puede recibir. A diferencia de una configuración proxy normal, los surrogates o proxy inversos se sitúan en las redes internas de los servidores web y no en las redes de los clientes. Esta diferencia radica en el propósito del proxy, ya que en la red del cliente se utilizan principalmente para filtrar y realizar funciones de monitorización de tráfico, y en cambio, un proxy inverso es una forma más eficaz de aligerar la carga de los servidores web acelerando los tiempos de respuesta. En comparación con el esquema inicial mostrado en la figura 4, este diseño le otorga un grado de complejidad tal y como puede verse en la figura 5. De esta forma, el gateway será el que recibe toda la carga que va destinada al servidor Apache (el servidor web) y responderá a todas la peticiones —capacidad por la cual también son llamados aceleradores web o surrogates—. En caso de que el proxy no disponga de ninguna copia en 16 Figura 5. Diseño red con Proxy memoria cache del objeto solicitado o la copia que tiene no esté actualizada, envía una solicitud al servidor original para obtener el recurso. Una vez el surrogate ha recibido la respuesta de Apache, éste almacena una copia en memoria para que disponga de ella en la siguiente ocasión, y finalmente, lo reenvía al cliente que lo solicitó originalmente. Además, estas copias no son permanentes ya que tienen un periodo de validez tras el cuál son borradas, evitando así la mala gestión por desperdicio de memoria. Así, el mecanismo de proxy inverso principalmente resuelve un inconveniente, el alto tiempo medio de respuesta de Apache frente a NGINX debido al gran número de componentes que Apache soporta y que carga en memoria, lo que ve afectado su rendimiento, consumiendo mas CPU y memoria RAM por cada petición que recibe. 3.3. Esquema objetivo. Otra variante (véase figura 6), que surge como resultado de una mezcla entre los dos esquemas anteriores y en la que podemos disponer de ambos servicios (surrogate y servidor web) instalados en el mismo equipo, es la que se desarrolla a lo largo de este trabajo. Este tipo de diseño elimina la necesidad de habilitar dos máquinas distintas para albergar cada uno de los servicios, simplificando el esquema —aunque no la configuración—. En este diseño el surrogate, NGINX en nuestro caso, se encuentra instalado en el mismo equipo que el servidor web Apache, con la característica fundamental de que el servicio que ha de permanecer a la espera de peticiones HTTP en el puerto 80 es el proxy —en realidad esto no es obligatorio ya que se pueden utilizar técnicas como el Port Forwarding (redirección de puertos) siempre y cuando se redireccione desde el puerto 80 (por defecto HTTP) hacia el puerto en que se encuentra el proxy—, y el servidor web (Apache) se configura en cualquier otro puerto alternativo en el cuál recibe las peticiones procedentes del surrogate. Así, a modo de resumen, la configuración del servidor queda de la siguiente forma: 17 Figura 6. Esquema con servidor proxy y web en la misma máquina Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web •NGINX configurado para atender peticiones HTTP en el puerto 80 de la IP 192.168.15.128 •Apache configurado a la espera de solicitudes HTTP en el puerto 9080 de la IP en la que se encuentren configurados los servidores virtuales, que son mencionados más adelante (por defecto 192.168.15.128). •Webmin con el módulo VirtualMin instalado y preparado en el puerto 10000 de la IP 192.168.15.128 El objetivo de este esquema es que NGINX sea el que responda todas las peticiones sirviendo el contenido estático, ya sean imágenes o documentos HTML (HiperText Markup Language)2, mientras que todo el contenido que sea generado de forma dependiente de los datos de la petición por medio de CGIs (dinámico), serán solicitadas al servidor Apache desde el proxy. Así, del párrafo anterior se puede deducir que NGINX funcionará como un servidor web normal —al margen de Apache— para todo el contenido estático, esto es posible ya que el servicio se encuentra en el mismo equipo que los recursos que conforman las webs, permitiendo al surrogate acceder al disco duro para su lectura de una forma mas eficiente, debido al uso de funciones nativas del sistema operativo, y posterior envío hacia el cliente. Además, NGINX será el encargado de cifrar y comprimir todas las comunicaciones pues, en estas tareas, es tambien más eficaz que Apache. Por otro lado, Apache —que tambien se encuentra instalado en el mismo servidor—, será el encargado de recibir desde NGINX las peticiones de los clientes para todo el contenido dinámico, es decir, aquel contenido que se genera en base a alguno de los valores incluidos en la petición, ya sea en las cabeceras o en el cuerpo de la misma. De esta forma, Apache sólo se ocupará de una parte mínima de todo el contenido que compone las webs alojadas en el servidor, y NGINX almacenará en su memoria cache aquellos recursos previamente generados por Apache, que se encargará de recuperar y transmitir a los clientes en caso de que éstos vuelvan a ser solicitados, actuando así, como un proxy o acelerador web. 2 Lenguaje de marcas para crear contenido web. Mas información en [42] 18 4. Implementación En primer lugar, se ha estudiado el funcionamiento interno de VirtualMin, así como sus ficheros de configuración y ejecutables, con el objetivo de conocer qué ficheros son necesarios para su lectura o modificación por parte de la herramienta desarrollada. Del mismo modo en que se ha estudiado el funcionamiento del panel, también se han analizado y comprendido los ficheros de configuración de Apache, que el propio VirtualMin modifica en función de las acciones que el administrador realice desde la interfaz del panel. Partiendo del análisis previo, se ha procedido a desarrollar los scripts de automatización en Python que realizan la integración, y posteriormente, se ha hecho un simple análisis estadístico, mediante el uso de una sencilla aplicación desarrollada en Java, para deducir con qué valores configurar NGINX de la forma más eficiente posible. Por último, haciendo uso de todo lo desarrollado de forma previa, se ha creado un módulo para el panel de control Webmin que posibilite de forma transparente, desde la interfaz, la integración de NGINX en modo proxy inverso con Apache para los servidores virtuales o webs gestionados desde VirtualMin. 4.1. Análisis de VirtualMin El primer paso en el desarrollo ha sido investigar el funcionamiento interno de VirtualMin, los ficheros que emplea, en los cuáles se almacenan los datos de configuraciones de los servidores virtuales que pueden ser gestionados desde el panel y los ejecutables que se lanzan cuando el administrador realiza una acción en el mismo. De esta forma y conociendo el funcionamiento de las herramientas en las que debíamos integrar nuestro desarrollo, nuestra aplicación es capaz interaccionar con VirtualMin modificando el contenido de los ficheros necesarios sin interrumpir el correcto funcionamiento del panel de control. El directorio de instalación de VirtualMin en CentOS es /usr/libexec/webmin/virtualserver/. Esto se debe a que, en realidad, VirtualMin no es mas que un módulo de Webmin llamado virtual-server, que aumenta las capacidades del panel, lo que hace necesario que éste último se encuentre instalado en el sistema para que VirtualMin funcione. En el interior del directorio de instalación de VirtualMin encontramos los archivos ejecutables que el panel lanza cuando el administrador realiza alguna acción desde la interfaz web, esto son: los CGI, los archivos con las configuraciones de los CGI, y los ficheros necesarios para que Webmin interprete correctamente el módulo. De la misma forma que el directorio con los ejecutables (CGI) se encuentra bajo el directorio de Webmin, dentro de /etc/webmin/ se localilzan los directorios con ficheros de configuración de los módulos instalados en dicho panel y, por lo tanto, también se encuentra el directorio correspondiente para VirtualMin, cuya ruta es /etc/webmin/virtual-server/. 19 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Dentro de este directorio, el archivo mas importante es el fichero config, cuyo contenido es un atributo de configuración con su valor asignado en cada linea, véase la figura 7. Este fichero es cargado en una variable de tipo hash3 (diccionario) cuando cualquier CGI del módulo realiza una llamada a la función init_config(), y además, es utilizado por el panel de control para permitir que los ajustes de configuración sean editables por el administrador, como son las rutas hacia otros ficheros de configuración u otras opciones para controlar el comportamiento del módulo. Es en este fichero en el que se encuentra la configuración de la plantilla por defecto que VirtualMin asigna en la creación de los distintos servidores virtuales para Apache, por lo que nuestros scripts deben modificar estos valores conforme a los requerimientos del administrador. Figura 7. Extracto del fichero config de VirtualMin modificado Ya analizados cuáles son los lugares en que se encuentran los ficheros de instalación y configuración del panel de control, es importante realizar una breve descripción de cuál es el comportamiento general del panel para entender mejor su funcionamiento. Una vez el equipo con el panel es puesto en marcha, tenemos una web de gestión disponible desde la que podremos utilizarlo, indicando en el navegador la dirección IP del servidor y el puerto en que se encuentre funcionando el servicio, que es el encargado de mostrar el resultado de los CGI que conforman el panel —pues estos, al fin y al cabo son ejecutables—. Esto es, el puerto 10.000 por defecto, quedando la url en nuestro servidor de pruebas como sigue https://192.168.15.128:10000. Véase figura 8. 3 Estructura de datos eficiente —también llamada array asociativo— en la que puede accederse a su contenido directamente a través de una clave “única” que tiene asociado un valor. 20 Figura 8. Acceso de Webmin en el servidor backup_feature_logrotate=1 mysql_chgrp=1 logrotate_config=rotate 5 weekly compress postrotate [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid` /etc/rc.d/init.d/httpd graceful ; sleep 5 endscript sharedscripts show_sysinfo=2 avail_mailboxes=1 defforceunder=0 alias_types=1,2,5,6,7,8,9,10,11,12,13 spam_lock=0 key_size=2048 webmin_ssl=0 Es preciso señalar que cuando iniciamos sesión en el panel se realiza el mismo proceso que cuando hacemos login en el equipo, es decir, se consultan los usuarios registrados en el servidor (contenidos por el fichero /etc/shadow) para permitirnos controlar el equipo. A continuación de que hemos iniciado la sesión en el equipo, el servidor web propio de Webmin situado en el puerto 10.000, será el encargado de leer del disco duro el CGI de inicio del panel, ejecutarlo y devolvernos el resultado que el navegador es el encargado de representar en pantalla. Este proceso se repite para todos los programas ejecutables que conforman el panel y que sean demandados por el administrador desde el navegador mediante los clics que éste realice en la interfaz. Cada uno de estos ejecutables esta compuesto por órdenes escritas en un lenguaje de programación concreto, que el servidor interpreta, recogiendo el resultado y retornándolo al origen de la petición. Por defecto, todos los CGI de VirtualMin están implementados en Perl, pero se otorga al desarrollador la libertad de elegir cualquier otro lenguaje, siempre y cuando el equipo disponga de un interprete instalado que sea capaz de entenderlo. 4.2. Análisis de Apache Una vez tenemos una idea mas clara del funcionamiento de VirtualMin, es necesario aclarar cómo funciona y se configura el servidor web Apache, sobretodo lo relativo a los servidores virtuales, ya que como hemos dicho antes, estos son con los que el panel trabaja. Partiendo de la configuración inicial de nuestro servidor de pruebas, Apache se encuentra instalado en /etc/httpd/ en cuyo interior se hayan dos directorios importantes conf y conf.d. El primero de ellos alberga los ficheros de configuración del servicio web, mientras que el segundo contiene los ficheros de configuración de los módulos que Apache tiene instalado. Dentro de /etc/httpd/conf/ el fichero mas importante, llamado httpd.conf, es el de configuración del servicio. Es en este fichero en el que podemos indicar por ejemplo el puerto o puertos en el que queremos que Apache se encuentre esperando peticiones web —Apache tiene la capacidad de poder escuchar simultaneamente peticiones en distintos puertos y direcciones IP—, a que rutas irá a buscar los documentos solicitados por las peticiones y, lo mas importante en este trabajo, los servidores virtuales. El formato de todos los ficheros de configuración de Apache consta de una directiva por cada linea, y por cada una de las directivas, sus argumentos han de estar separados por un espacio en blanco. En caso de que el valor de una directiva contenga espacios, este debe ir entre comillas (“”). Todas las directivas se aplican al servidor. Sin embargo, el alcance de las directivas puede limitarse agrupándolas en bloques, en cuyo caso, éstas solo se aplican a una parte del servidor[37]. Cada sección va delimitada al principio por el nombre de la sección encerrado entre <>, y al final, por </>. Podemos encontrar bloques de los siguientes tipos: <Directory>, <DirectoryMatch>, <Files>, <FilesMatch>, <Location>, <LocationMatch>, y <VirtualHost>[37]. A continuación, en la figura 9, se muestra un extracto correspondiente al fichero de configuración de Apache en el servidor relativo a gestión de procesos, lo que nos da un ejemplo de cómo se organiza la información en éste tipo de archivos. 21 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Listen 80 NameVirtualHost 172.20.30.40 <VirtualHost 172.20.30.40> DocumentRoot /www/example1 ServerName www.example.com </VirtualHost> <VirtualHost 172.20.30.40> DocumentRoot /www/example2 ServerName www.example.org </VirtualHost> <VirtualHost 172.20.30.40> DocumentRoot /www/example3 ServerName www.example3.net </VirtualHost> # IP-based <VirtualHost 172.20.30.50> DocumentRoot /www/example4 ServerName www.example4.edu </VirtualHost> <VirtualHost 172.20.30.60> DocumentRoot /www/example5 ServerName www.example5.gov </VirtualHost> Figura 9. Extracto httpd.conf para configuración de VirtualHost De todos los bloques que contiene el fichero de configuración, para este trabajo los mas importantes son los correspondientes a los servidores virtuales, es decir, las secciones <VirtualHost>. Un servidor virtual es la capacidad de Apache para servir diferentes sitios web ubicados en un mismo equipo, diferenciándolos por su nombre (name-based) —indicado por la directiva ServerName— o, puerto o dirección IP destino de las peticiones (IP-based)[36]. En caso de servidores virtuales name-based, las directivas tipo NameVirtualHost indican a Apache que debe diferenciar por el nombre los servidores configurados en la dirección IP y el puerto que acompañan al parámetro. De esta forma cuando reciba peticiones web a través de la interfaz de red que tenga dicha dirección IP, Apache comprueba que el nombre de la web (ServerName) coincida con el valor indicado en el campo Host de la cabecera HTTP. Véase la figura 9 extraída de la documentación de Apache [33]. Por otra parte, en el directorio /etc/httpd/conf.d/ se ubican todos los ficheros de configuración necesarios para los distintos módulos de Apache que tengamos instalados en el servidor, como por ejemplo los ficheros de configuración del módulo de soporte para PHP (/etc/httpd/conf.d/php.conf). 4.3. Desarrollo La idea básica del desarrollo consta de la realización de los scripts que realizan el proceso de integración de NGINX para las configuraciones del servidor web Apache desplegadas en Virtualmin. Posteriormente, se detalla el proceso de desarrollo de un módulo para el panel 22 Webmin que haga uso de los ejecutables previamente desarrollados para su facil ejecución desde el panel. Después de analizar las herramientas con las que debemos realizar la integración, el siguiente paso es detallar el contenido de los scripts de integración y el desarrollo del módulo para Webmin desde el que se puedan gestionar de forma fácil. 4.3.1 conf.file Debido a la flexibilidad que se ha querido otorgar al desarrollo, los scripts se han ideado con la propiedad característica de que puedan ser configurados de forma fácil indicando valores a los campos de un fichero de configuración. Este fichero contiene los parámetros importantes —tales como rutas de instalación por defecto, que pueden variar en función de la distribución Linux— que el administrador puede especificar para asegurar el correcto funcionamiento de la integración en su sistema. Además, también se almacenan en este archivo los datos de los ficheros de configuración de los servicios, que se leen durante la ejecución y que son necesarios para su posterior uso. El contenido de conf.file es leído al inicio de cada script por la función cargaConf(), perteneciente al módulo nginxReverselib, y cargado en una variable de tipo diccionario llamada config, que será accesible durante la ejecución de los mismos. Así, el fichero conf.file contiene los siguientes parámetros (véase figura 10): •Número de puerto HTTP alternativo para Apache. Puerto hacia el que se redirigirán las peticiones HTTP desde el proxy. Sintaxis nPuertoAp: numero Valor por defecto: 9080 •Numero de puerto SSL alternativo para Apache. Puerto en el que se configurarán los VirtualHost para atender peticiones SSL provenientes del proxy. Por defecto, la configuración de Apache atiende sólamente peticiones a través de HTTP. Aun así, es posible habilitar ésta característica si se quiere que la comunicación entre NGINX y Apache sea cifrada (HTTPS). Sintaxis nPuertoApSSL: numero Valor por defecto: 9443 •Ruta hacia el fichero de configuración de Apache. Sintaxis nfConfApache: ruta Valor por defecto: /etc/httpd/conf/httpd.conf •Dirección IP del servidor donde NGINX ha de atender peticiones para los servidores virtuales de Apache. Sintaxis IP: ip Valor por defecto: sin valor 23 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web •Ruta hacia el fichero que contiene la plantilla por defecto de VirtualMin. Éste parámetro solo es necesario que sea modificado en caso de que el panel se encuentre instalado en otro lugar. Sintaxis nfPlantilla: ruta Valor por defecto: /etc/webmin/virtual-server/config •Directorio de instalación por defecto de NGINX. En caso de haber instalado NGINX en otro lugar ha de indicarse la ruta en este campo. Sintaxis rutaNginx: ruta Valor por defecto: /etc/nginx/ •Ruta hacia el fichero de configuración del módulo SSL de Apache. Sintaxis nfConfSSLApache: ruta Valor por defecto /etc/httpd/conf.d/ssl.conf •Ruta hacia el fichero de configuración del módulo RPAF. En caso de ya encontrarse instalado, ruta hacia el fichero. En caso contrario, lugar donde se creará. Sintaxis nfConfRPAF: ruta Valor por defecto: /etc/httpd/conf.d/mod_rpaf.conf •Ruta por defecto en el sistema donde se encuentra el fichero de configuración de NGINX en caso de encontrarse instalado. Ruta donde comprobará si está instalado. Sintaxis nfConfNGINX: ruta Valor por defecto: /etc/nginx/nginx.conf 4.3.2 Libreria nginxReverselib.py En primer lugar, todos los métodos comunes que los scripts de integración utilizan durante su ejecución se han incluido en un fichero llamado nginxReverselib.py, que hace las funciones de librería. De esta forma, los scripts de integración incluyen este fichero como referencia — mediante la orden import nginxReverselib—, para mantener acceso a las funciones, las cuáles son llamadas de la siguiente manera: modulo.funcion(parametros). Así, la librería de los scripts de integración contiene las siguientes funciones: 24 Figura 10. Contenido del fichero conf.file •cargaConf() Esta función realiza la lectura del fichero conf.file y carga su contenido en la variable de tipo diccionario config. •GuardaConf() Almacena el contenido de la variable config en el fichero conf.file de forma que los cambios realizados en la configuración por los scripts sean salvados para la siguiente ejecución. •imprimeConf() Imprime el contenido del fichero conf.file •leeFichero(nombre) Realiza la lectura del fichero que se encuentra en la ruta indicada por el valor del parámetro nombre, devolviendo una variable tipo lista con el contenido leído. •escribeFichero(fich, conf) Escribe en el fichero indicado por el valor de la variable fich el contenido de la varable tipo lista conf. •lsDir() Lista el contenido del directorio que recibe como parámetro. En caso de no recibir ningun parámetro, por defecto devuelve el listado del contenido del directorio actual (./). •log() Escribe en el fichero de registro nginxReverse.log el contenido de la variable que recibe como parámetro. De esta forma y, haciendo uso de esta función, se van registrando todas las operaciones que realiza el código de los scripts facilitando las tareas de depuración de errores o mala configuración de los servicios. A modo de aclaración, el contenido del fichero librería puede observarse en la figura 11. 25 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Una vez hecho esto, se pasa el bloque entero, junto con la IP y el puerto, y se comprueba si ha sido ya procesado —no se encuentra configurado para NGINX— o si no ha sido excluido en la configuración de los scripts (marcado para no configurar). Realizada esta comprobación, se procede a crear el fichero que contendrá las directivas relativas a cada web en el proxy. Cabe destacar, que para cada servidor virtual se crea un fichero de configuración independiente, facilitando las tareas de administración y proporcionando flexibilidad en las configuraciones (véase la figura 17 y figura 18). 32 Figura 17. Extracto Ap2Nginx.py. Comprueba configuración VirtualHost. Como apunte importante, es necesario remarcar que la configuración por defecto establecida en éstos archivos requiere que se incluyan en el directorio raíz de las webs —ubicado dentro del directorio /home/ del sistema— los ficheros relacionados con las conexiones HTTPS, es decir, tanto el fichero que contiene el certificado, llamado ssl.cert, y que se envía al usuario para cifrar las conexiones; como el que contiene la clave privada del servidor virtual, llamado ssl.key, utilizada para descifrar la información. 4.3.5 Configuración de Virtual Servers en NGINX Una vez hemos visto qué operaciones realizan los scripts para realizar la configuración como proxy inverso de Apache, detallaremos el contenido de los ficheros que se han creado en NGINX para arrojar luz sobre los ajustes implementados. En primer lugar y como elemento guía de nuestras configuraciones, se ha llevado a cabo un estudio estadístico que analiza el tamaño de los recursos para varias webs. De esta forma tenemos una visión mas clara acerca de que parámetros otorgar al surrogate. Véase el Anexo 1. Volviendo a los ficheros de configuración para NGINX. El contenido del archivo principal de configuración del servicio, llamado nginx.conf, alberga las directivas que son comunes y se aplican a todos los servidores virtuales que contiene el surrogate. Dentro de este fichero, las directivas empleadas, distribuidas por el contexto al que se aplican, son: •user apache; 33 Figura 18. Extracto Ap2Nginx.py. Configuración para NGINX Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Se usa para indicar el usuario con el que se ejecutan los workers, es decir, los procesos que atienden las peticiones. En este caso, apache es el usuario por defecto que tiene acceso al contenido de los servidores virtuales ya que VirtualMin utiliza éste usuario en su creación. Contexto: main •worker_processes auto; Número de procesos worker que atienden peticiones y gestionan las conexiones. NGINX adecuará éste valor en función del número de CPUs que contenga el servidor. Contexto: main •worker_connections 2048; Número máximo de conexiones simultaneas que puede atender un worker. Contexto: events •use epoll; Método de procesado de conexiones. epoll es un método eficiente usado en los kernels de Linux a partir de la versión 2.6. Contexto: events •log_not_found on; Habilita el registro en el error log para ficheros no encontrados. De esta forma, NGINX incluira aquellas peticiones que obtengan un codigo de respuesta 404. Contexto: http •include /etc/nginx/mime.types; Agrega el contenido del fichero mime.types situado en /etc/nginx a la configuración. Este fichero contiene directivas para soportar envío y recepción de contenido codificados con estos tipos de codificación estándar. Contexto: http •proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=zonacache:30M max_size=100M; Esta directiva indica al proxy la configuración relativa a la cache. En este caso, el lugar en disco en que se almacenan los objetos cacheados es /var/nginx/cache. Esta ruta de cache contendrá 2 niveles de subdirectorios que se crearán en función del hash obtenido a partir de los datos del objeto. Las claves se almacenan en una parte de la memoria compartida que tiene el nombre de zonacache y un máximo de 30MB. Según la documentación de NGINX, 1MB de memoria puede llegar a albergar cerca de 8000 claves, por lo que en caso de que el numero de claves sea tan alto que los objetos sobrepasen los 100MB en disco, el proceso de gestión borrará las entradas menos usadas. Contexto: http •sendfile on; Permite hacer uso de la funcion del kernel sendfile, mucho mas efectiva para realizar lecturas del disco, acelerando este proceso. Contexto: http 34 •tcp_nodelay on; Permite ignorar el mecanismo implementado por el algoritmo de Nagle4, que obliga a que todos los paquetes estén completos —tamaño igual al MTU5 de la red— antes de ser enviados. La activación de la directiva tcp_nodelay permite que los paquetes sean enviados tan pronto como sea posible, evitando así, retardos en las respuestas. Contexto: http •tcp_nopush on; Combinado con sendfile, la activación de esta directiva hace que NGINX espere a que el contenido de la respuesta alcance el MTU (Maximum Transmission Unit) de la red, evitando la sobrecarga de la misma. Cuando una lectura con sendfile no llega al MTU se deshabilita esta opción y entra en funcionamiento tcp_nodelay. Contexto: http •gzip on; Junto con las opciones siguientes del fichero, habilita la compresión del contenido de las respuestas para todos los tipos MIME indicados en gzip_types, siempre y cuando el navegador del cliente no sea Microsoft Internet Explorer 6 (gzip_disable) —en el que no funciona bien la descompresión— y el tamaño de la carga sea superior a 1100Bytes (gzip_min_length). El nivel de compresión, además, viene determinado por las características del compresor, que a partir del nivel 2 reduce poco el tamaño del fichero comprimido en proporción al uso de CPU (véase el análisis de Gzip desarrollado en el Anexo 2). Contexto: http •keepalive_timeout 10s; Tiempo máximo que espera NGINX antes de cerrar una conexión en que no recibe ninguna petición. En el valor indicado en la configuración del servicio, se establece un tiempo pequeño para evitar la infrautilización del servidor teniendo conexiones inactivas. Contexto: http •client_header_buffer_size 2k; y large_client_header_buffers 4 2k; Tamaño de los buffers de recepción de cabeceras HTTP por cada conexión para las peticiones. En caso de que el tamaño de cabeceras de una petición sea mayor de 2KBytes se aplica el parámetro large_client_header_buffers. Contexto: http •client_body_buffer_size 64k; y client_max_body_size 100M; 64KBytes es el tamaño del buffer que almacena el contenido (payload) de cada petición. Además, el tamaño máximo de envío de datos del cliente por petición POST 4 Más información sobre el funcionamiento del algoritmo de Jonh Nagle en [14] 5 Tamaño máximo de payload (carga útil) junto con las cabeceras para un datagrama TCP. En Ethernet 1500Bytes. 35 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web es de 100MBytes. Este último parámetro ha de ser adecuado a las necesidades de las webs ya que puede ser un problema de seguridad habilitar un tamaño excesivo debido al consumo de ancho de banda necesario para enviar al servidor tales cantidades de datos. Contexto: http •send_timeout 10s; En el caso de que transcurran 10 segundos entre dos escrituras para un mismo cliente en una misma respuesta, NGINX cierra la conexión para evitar el despilfarro de recursos. Contexto: http •output_buffers 4 32k; Tamaño y número de buffers para leer una respuesta almacenada en el disco duro, en nuestro caso un objeto estático. Basándonos en el análisis estadístico anterior (Anexo 1), podemos apreciar que el 97% de los elementos de las webs analizadas tenían un tamaño igual o inferior a 128KBytes, que es el máximo fijado para los buffers de lectura de disco (4 x 32KB = 128KB). Contexto: http •include /etc/nginx/conf.d/*.conf; NGINX incluirá los ficheros de configuración —aquellos con extensión .conf— que se encuentran en el directorio /etc/nginx/conf.d/. Si nos fijamos, es en éste directorio en que el script Ap2Nginx.py ubica los ficheros de configuración para NGINX de los servidores virtuales detectados en Apache, de esta forma es como el proxy carga las distintas configuraciones para cada uno de ellos. Contexto: http Así, el contenido de este fichero es el que puede apreciarse en la figura 19. 36 Por otro lado, las configuraciones especificas a cada una de las webs se distribuyen en ficheros separados tal y como se ha tratado en el punto 4.3.3, donde se explica el funcionamiento del script Ap2Nginx.py. Estos ficheros contienen las directivas que se aplican por separado a cada servidor virtual que, en NGINX, vienen determinados por el bloque server, en cuyo interior se encuentran. Ademas, es necesario aclarar que cada fichero de configuración para un servidor virtual contiene dos bloques de directivas server. El primero de estos bloques sirve para indicar al cliente que debe usar el protocolo HTTP con cifrado, o lo que es lo mismo, HTTPS, comunicando a todas las peticiones que se reciben por el puerto 80 (HTTP) que deben hacerlo al 443 (HTTPS). Para ello, el bloque server ubicado en el pueto 80 envía una respuesta con un código de estado 301 Moved Permanently que obliga al navegador a realizar todas las peticiones posteriores usando la dirección que lo acompaña, y además, agrega la cabecera Strict-Transport-Security —habilitando el mecanismo HSTS— que indica al navegador del cliente que sólo debe comunicarse por HTTPS con el servidor[7]. 37 Figura 19. Contenido de nginx.conf Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web De esta forma, el navegador del cliente realizará las conexiones sucesivas al puerto 443. Es el segundo bloque de directivas el que contiene la configuración HTTPS para el servidor virtual. Así, los parámetros que el script Ap2Nginx.py otorga por defecto durante su ejecución para este bloque son los siguientes: •listen 192.168.15.128:443; La directiva listen se utiliza para indicar la dirección IP y el puerto en el que se atienden peticiones para ese servidor virtual. Por defecto, el valor que se aplica para la dirección es el que obtiene en la lectura del fichero de configuración de Apache para los VirtualHost. •server_name prueba.com www.prueba.com; La directiva server_name indica los nombres de un servidor virtual. Estos valores se comparan con el del campo de cabecera Host de la petición HTTP para aplicar la configuración específica para cada web. •root /home/prueba/public_html; Directorio en el que se encuentran los recursos que conforman la web almacenados en el disco duro, al cuál se accede para su lectura y posterior envío cuando son solicitados. •ssl on; Habilita el cifrado de las comunicaciones HTTP. •ssl_certificate /home/prueba/ssl.cert; Certificado digital con información que identifica el propietario del sitio web y que contiene la clave pública (cifrado asimétrico6), que los clientes usarán para cifrar el intercambio de clave7. Por defecto, el nombre asignado es ssl.cert y se ubica en la raíz del directorio del usuario propietario del servidor virtual. Éste certificado puede ser obtenido de una entidad certificadora, de forma que constate la información del servidor, o puede ser creado por nosotros mismos y estar autofirmado. El proceso de creación de la solicitud de firma de certificado (necesaria para el método con autoridad certificadora) y de autofirmado se ha detallado en el Anexo 3. •ssl_certificate_key /home/prueba/ssl.key; Ruta hacia el fichero que contiene la clave privada con la que se ha firmado digitalmente el certificado, además, esta clave se utiliza para descifrar los datos que se reciben del cliente —previamente cifrados con nuestra clave pública— durante el proceso de negociación de la conexión segura. Por defecto el nombre asignado es 6 Más información acerca del cifrado asimétrico puede encontrarse en [38] 7 Más información acerca del cifrado híbrido puede encontrarse en [38] 38 ssl.key y se ubica en la raíz del directorio del usuario propietario del servidor virtual. Esta clave es necesario que sea creada por nosotros mismos para obtener el certificado digital independientemente de cualquiera de las formas mencionadas en el punto anterior, ya sea a través de una CA (Autoridad Certificadora) o autofirmado. El proceso de obtención de la clave privada se encuentra detallado en el Anexo 3. •ssl_ciphers HIGH:!aNULL:!MD5; Esta directiva indica a NGINX que sólo debe usar cifrados fuertes. En este caso rechazamos el uso de los algoritmos MD5 y aNULL (ADH y AECDH), todos ellos vulnerables. •ssl_protocols TLSv1 TLSv1.1 TLSv1.2; Al igual que la directiva anterior, sólo usamos protocolos criptográficos fuertes, como es TLS8. •ssl_prefer_server_ciphers on; Se indica a NGINX que deben prevalecer en la negociación los cifrados ofrecidos por el servidor en vez de los del cliente. •ssl_session_cache shared:SSL:10m; y ssl_session_timeout 10m; Establecemos una memoria compartida por todos los workers en la que se almacenan durante 10 minutos (ssl_session_timeout) los parámetros de las sesiones SSL, para evitar su renegociación —que es la parte más costosa del proceso— en caso de un mismo cliente. •access_log /var/log/virtualmin/prueba.com_access_log; y error_log /var/log/virtualmin/prueba.com_nginx_error_log; VirtualMin por defecto establece que los ficheros de log de los servidores virtuales en Apache registren los fallos y accesos en los ficheros anteriores. Puesto que ya no es Apache sino NGINX el encargado de recibir todo el trafico, éstos se establecen con el mismo nombre que les otorga VirtualMin, de forma que éste sea capaz de interpretarlos. •location = /robots.txt { … } Cada vez que se recibe una petición, NGINX busca el bloque de directivas location que más se ajusta a la URI que el cliente ha solicitado para aplicarle las políticas que en su interior se hallan. Cuando el recurso solicitado es /robots.txt, se aplican las directivas de permitir acceso a todo el mundo sin mantener un registro de accesos para el recurso. 8 Transport Layer Security (TLS) es un protocolo que proporciona comunicaciones privadas en Internet [2]. 39 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web •location ~* ^.+\.(js|jpeg|jpg|gif|png|ico|css|zip|tgz| gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mp3|htm|html|xml) $ { … } Al igual que el bloque anterior, cuando la URI solicitada por el cliente encaja con la expresión regular que lo acompaña —tiene una extensión de entre las que se encuentran entre paréntesis— , será NGINX el que accede al directorio indicado por la directiva root para leer el recurso y servirlo (try_files $uri $uri/ =404;). En caso de que no encuentre el recurso, devolverá un codigo de respuesta 404-Not found. Además, la directiva gzip_static on; indica al surrogate que siempre debe comprimir las respuestas de contenido estático si el cliente lo soporta. •location ~ /\.ht { … } Por seguridad, se deniega el acceso a todos los ficheros cuyo nombre empieza por .ht. Recordemos que los ficheros .htaccess de Apache contienen información importante acerca de las políticas del servidor para cada directorio. Esta directiva impide (deny all;) el acceso a este tipo de ficheros. •location / { … } Este bloque de directivas, es el que establece que, en caso de no cumplirse ninguno de los bloques location explicados anteriormente, NGINX realice la petición a Apache (proxy_pass) aplicándole las directivas de configuración del fichero /etc/nginx/proxy.conf, es decir, hace que Apache sirva todo el contenido que no sea estático. A modo de ejemplo, en la figura 20 puede verse el contenido del fichero de configuración para la web prueba.com ubicada en el servidor de pruebas. 40 Una vez hemos visto las políticas con que son configurados por defecto los servidores virtuales en NGINX, el comportamiento como proxy del surrogate viene definido en el fichero al que se ha hecho referencia anteriormente —recordemos que para cualquier recurso no estático NGINX realiza las peticiones a Apache—, este es, /etc/nginx/proxy.conf. A continuación se detalla el contenido de éste fichero: •proxy_set_header Host $host; Establece la cabecera Host con el valor que se recibe en la petición por parte del cliente, si no existe este campo de cabecera (HTTP/1.0), se sustituye por el nombre del servidor NGINX. •proxy_set_header X-Real-IP $remote_addr; Se añade una cabecera para que Apache conozca la dirección del cliente que realizó originalmente la petición a fin de que pueda llevar un registro de sucesos correcto. 41 Figura 20. Contenido del fichero prueba.com.conf Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web correcto funcionamiento de los scripts de integración por lo que habrán de ser cambiados conforme a las características del sistema en que se ejecute el módulo. Por otro lado, en la figura 25 se puede ver el código encargado de recibir y almacenar en el fichero de configuración del módulo los cambios realizados, que son enviados por config.cgi una vez el administrador hace clic en el botón “Salvar” del formulario. •allmaual_form.cgi y allmanual_save.cgi El primero de ellos, muestra al administrador el contenido del fichero de configuración de NGINX que previamente haya sido seleccionado de una lista desplegable. El segundo, por otro lado, almacena los cambios que se hayan realizado en estos ficheros cuando el administrador pulsa el botón “Salvar”. Véanse las figuras 26 y 27. 48 Figura 25. Código de config_save.cgi Mientras que la figura 26 muestra la interfaz desde la que se pueden realizar los cambios en el fichero seleccionado de la lista desplegable ubicada en la parte superior de la pantalla, en la figura 27 se puede apreciar el código encargado de almacenar los cambios en el fichero correspondiente. •list_vs.cgi, edit_vs.cgi y drop_vs.cgi list_vs.cgi genera un listado que contiene los servidores virtuales configurados en NGINX. Para ello, lee el directorio donde se almacenan los ficheros de los servidores virtuales del proxy. Si el administrador hace clic en el nombre de dominio de uno de ellos, edit_vs.cgi muestra la información basica de esa web y solicita la confirmación 49 Figura 26. Interfaz de allmanual_form.cgi Figura 27. Código allmanual_save.cgi Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web para deshabilitar el servidor virtual en el surrogate. En caso afirmativo, drop_vs.cgi es el encargado de borrar el fichero de configuración de esa web en NGINX y por lo tanto, inhabilitándolo para recibir peticiones en el proxy. Cabe destacar que este proceso sólamente borra el fichero y añade el nombre de dominio a una lista de excepciones de configuración, para que, en caso de que se vuelva a realizar la integración, no sea configurado. De forma que si se desea reconfigurar cualquier web que se encuentre en la lista de excepciones, basta con eliminarla desde el formulario de configuración del módulo. Sin embargo, la configuración para ese servidor virtual en Apache no se verá alterada y permanecerá en el puerto alternativo para no entrar en conflicto con el surrogate. El contenido de éstos CGI puede verse en las figuras 28, y 29. Este módulo, un empaquetado en .tar de todos los elementos que lo conforman, renombrado con formato .wbm, puede ser instalado fácilmente en Webmin desde el propio panel. Para ello, en el apartado Webmin/Configuracion de Webmin/Modulos de Webmin disponemos de un formulario desde el que seleccionamos el módulo a cargar. Tal y como puede verse en la figura 30, basta con pulsar sobre el botón Instalar módulo de la interfaz para que nuestro desarrollo quede incluido en el panel. En nuestro caso, el módulo desarrollado, queda incluido en la sección “servidores” del panel con el nombre de NGINX como proxy inverso de Apache. 50 Figura 28. Interfaz de list_vs.cgi Figura 29. Interfaz de edit_vs.cgi 51 Figura 30. Formulario de carga de módulos en Webmin Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 52 5. Pruebas 5.1. Sistema proxy inverso Una vez finalizado el desarrollo de los scripts y el módulo para el panel Webmin, la siguiente fase era la comprobación del correcto funcionamiento y configuraciones que éstos mismos establecen. De esta forma, la primera parte de las pruebas consistía en la comprobación de que las configuraciones establecidas por los módulos desarrollados eran las deseadas, logrando que el sistema funcionase de la forma adecuada. Para ello se han realizado peticiones HTTP desde la maquina host —que actuaba como cliente— y observado las cabeceras del protocolo en la respuesta. En concreto, se utilizaba la orden curl para realizar ésta función indicándole mediante el parámetro -H, el valor de la cabecera Host: el servidor virtual en concreto para el que se deseaba comprobar su funcionamiento, en nuestro caso prueba.com. Así, la orden, junto con su resultado, pueden verse en la figura 31. Tal y como puede verse en la imagen anterior, el servidor que responde a nuestra petición es NGINX, que atiende las peticiones en el puerto HTTP (80) donde lo habíamos configurado. Además, y debido a la configuración por defecto que aplicamos a todos los servidores virtuales (véase el apartado 4.3.5) para habilitar el mecanismo HSTS —que fuerza conexiones seguras bajo HTTPS—, el código de respuesta que NGINX nos remite es el 301, indicándonos una redirección 53 Figura 31. Forzar HTTPS Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web hacia la página indicada por el campo de cabecera Location; que como se puede apreciar es una dirección bajo HTTPS (Location: https://www.prueba.com/). Siguiendo con las pruebas, y con la intención de comprobar que NGINX redirige las peticiones hacia Apache, es decir, que el mecanismo de proxy inverso se encontrara correctamente desplegado, se ha repetido la orden curl cambiando la dirección por la que NGINX nos había recomendado en la respuesta anterior. De ésta manera, el resultado obtenido puede verse en la figura 32. En la imagen anterior podemos apreciar en primer lugar cómo se realiza la fase de negociación de la conexión segura en la que se pactan los parámetros de la conexión, entre ellos, el protocolo de cifrado y el intercambio de claves. Si nos fijamos en la respuesta de la petición, observamos que quien responde a nuestra petición es NGINX (cabecera Server), y además, nos envía una cabecera de tipo ETag12 para control de versiones de cache. Por último, al final de las lineas de cabecera de la respuesta se muestra el contenido del recurso solicitado, en este caso, el texto “prueba.com”. Con el fin de asegurarnos que para ésta prueba es NGINX el realiza las funciones de servidor web, esto es, quien lee del disco duro el fichero index.html —cuyo contenido es el mostrado en la 12 The entity tag MAY be used for comparison with other entities from the same resource [3]. 54 Figura 32. Petición HTTPS a prueba.com respuesta de la figura 30— para servirlo al cliente, se ha comprobado el fichero de log de acceso que NGINX mantiene y en el que se va añadiendo una linea por cada petición que éste recibe. Así, en caso de que NGINX fuera efectivamente el que realizaba el procedimiento de leer un recurso estático solicitado y responderlo al cliente sin intervención de Apache, encontraríamos en su fichero de log /var/log/virtualmin/prueba.com_access_log la entrada correspondiente a dicha petición, y sin embargo, en el fichero de registro de acceso de Apache /var/log/virtualmin/prueba.com_apache_access_log no existiría su equivalente. En la figura 33, se puede apreciar cómo la fecha y hora (GMT) de la petición mostrada por la figura 32 coincide con la última entrada del fichero de registro de acceso para NGINX (GMT+2), mientras que en el log de Apache no aparece, corroborando el hecho anterior. Por último, se ha comprobado el comportamiento de NGINX en caso de solicitarse un recurso dinámico al servidor, en cuyo caso, debía reenviar las peticiones hacia Apache, esperar la respuesta del mismo, y devolverla al cliente. Esto es, comportarse como un proxy inverso. El procedimiento llevado a cabo es similar al anterior, con la diferencia que, en éste caso la petición debía registrarse en ambos ficheros de registro de acceso. El CGI solicitado, llamado ejemplo.php, se encargaba de generar código HTML de forma dinámica mediante la ejecución de la función phpinfo() desde el servidor Apache. En la figura 34 se puede ver la petición HTTPS realizada con el comando curl (la respuesta ha sido cortada debido a su extensión). 55 Figura 33. Últimas dos entradas en logs de NGINX y Apache Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Así, en la figura 35 se puede apreciar el contenido de los ficheros de registro después de realizar la petición anterior. Tal y como cabe esperar, ambos servicios registran la petición, lo que indica el correcto funcionamiento del diseño mostrado en el apartado 3.3. 56 Figura 34. Petición HTTPS ejemplo.php Figura 35. Contenido logs NGINX y Apache 5.2. Compresión de recursos El cometido principal de la realización de estas pruebas era la comprobación y demostración del funcionamiento de las configuraciones aplicadas relativas a la compresión de los recursos mediante Gzip. Las directivas detalladas en el apartado 4.3.5 indican a NGINX que debe comprimir el contenido de las respuestas siempre que se cumplan los requisitos especificados en la configuración y el cliente haya indicado que soporta la compresión. Para ello, el cliente indica al servidor que puede recibir el contenido de las respuestas comprimido en este formato mediante la inclusión de la cabecera HTTP Accept-Encoding: gzip. Un ejemplo de una petición realizada utilizando este método puede verse en la figura 36, en la que se solicita —haciendo uso de la orden de Linux curl e indicando que solo queremos visualizar las cabeceras de la respuesta— el recurso corto.txt de la web prueba.com albergada en nuestro servidor. Tal y como se aprecia en la imagen anterior, pese a que indicamos a NGINX que soportamos la compresión del contenido de las respuestas, el tipo de datos de la respuesta remitida por el servidor, indicado por la cabecera Content-Type, es texto plano (text/plain) sin ningún tipo de codificación especial. Esto se debe a que en la configuración del servicio, uno de los requisitos para comprimir los recursos es que su tamaño sea mayor de 1100Bytes, y sin embargo, en este caso el tamaño del recurso solicitado es de 28Bytes —indicado por el valor de la cabecera Content-Length—. Con el fin de probar lo anterior, se ha realizado el mismo procedimiento que en el caso del recurso corto.txt para un fichero de texto cuyo tamaño fuese superior al mínimo indicado en la configuración del surrogate. En esta ocasión, el contenido de la respuesta obtenida para la petición del fichero largo.txt, cuya longitud es de 16383Bytes, es enviada por NGINX comprimida, tal y como indica la cabecera Content-Encoding: gzip de la respuesta mostrada en la figura 37. 57 Figura 36. Petición indicando soporte gzip Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web [15] Nedelcu, Clément (2013). Nginx HTTP Server (2nd Edition). Birmingham: Packt Publishing. [16] Netcraft. February 2015 Web Server Survey. <http://news.netcraft.com/archives/2015/02/24/february-2015-web-serversurvey.html>[Consulta: 26 de Marzo de 2015] [17] NGINX, Inc. NGINX Reverse Proxy. <http://nginx.com/resources/admin-guide/reverse-proxy/>[Consulta: 2 de Junio de 2015] [18] NGINX, Inc. NGINX Content Caching. <http://nginx.com/resources/admin-guide/caching/>[Consulta: 2 de Junio de 2015] [19] Nginx.org. Configuration file measurement units. <http://nginx.org/en/docs/syntax.html>[Consulta: 26 de Marzo de 2015] [20] Nginx.org. Core functionality. <http://nginx.org/en/docs/ngx_core_module.html>[Consulta: 30 de Mayo de 2015] [21] Nginx.org. Nginx HTTP Core Module. <http://nginx.org/en/docs/http/ngx_http_core_module.html>[Consulta: 30 de Mayo de 2015] [22] Nginx.org. Nginx HTTP Proxy Module. <http://nginx.org/en/docs/http/ngx_http_proxy_module.html>[Consulta: 2 de Junio de 2015] [23] Nginx.org. Nginx HTTP SSL Module. <http://nginx.org/en/docs/http/ngx_http_ssl_module.html>[Consulta: 2 de Junio de 2015] [24] Nginx.org. Configuring HTTPS servers. <http://nginx.org/en/docs/http/configuring_https_servers.html>[Consulta: 2 de Junio de 2015] [25] Nginx.org. Nginx about page. <http://nginx.org/en/>[Consulta: 26 de Marzo de 2015] [26] Nginx.org. Nginx spanish wiki. <http://wiki.nginx.org/NginxEs>[Consulta: 26 de Marzo de 2015] [27] Open Source Initiative. The BSD 2-Clause License. <http://opensource.org/licenses/BSD-2-Clause>[Consulta: 27 de Marzo de 2015] [28] Python Software Foundation. General Python FAQ. <https://docs.python.org/2/faq/general.html#what-is-python>[Consulta: 27 de Marzo de 2015] [29] Rivest, R. (1992). The MD5 Message-Digest Algorithm. <http://tools.ietf.org/html/rfc1321>[Consulta: 26 de Marzo de 2015] 64 [30] Sslshoper.com (2010). How to Create and Install an Apache Self Signed Certificate <https://www.sslshopper.com/article-how-to-create-and-install-an-apache-selfsigned-certificate.html>[Consulta: 29/06/2015] [31] Stallings, William (2007). Data and computer communications (8ed). USA: Pearson Education. [32] The Apache Software Foundation. Licenses. <http://www.apache.org/licenses/>[Consulta: 23 de Marzo de 2015] [33] The Apache Software Foundation. Name-based Virtual Host Support. <http://httpd.apache.org/docs/2.2/vhosts/name-based.html>[Consulta: 5 de Junio de 2015] [34] The Apache Software Foundation. About the Apache HTTP Server Project. <http://httpd.apache.org/ABOUT_APACHE.html>[Consulta: 23 de Marzo de 2015] [35] The Apache Software Foundation. Apache HTTP Server Tutorial: .htaccess files. <http://httpd.apache.org/docs/2.2/howto/htaccess.html>[Consulta: 26 de Marzo de 2015] [36] The Apache Software Foundation. Apache Virtual Host documentation. <http://httpd.apache.org/docs/2.2/vhosts/>[Consulta: 5 de Junio de 2015] [37] The Apache Software Foundation. Configuration Files – Apache HTTP Server Version 2.4. <https://httpd.apache.org/docs/current/configuring.html>[Consulta: 18 de Mayo de 2015] [38] The Free Software Foundation (1999). Guía de “Gnu Privacy Guard”. <https://www.gnupg.org/gph/es/manual/book1.html>[Consulta: 5 de Junio de 2015] [39] Villamil, Frederic de (2014). Nginx Optimization: understanding sendfile, tcp_nodelay and tcp_nopush. <https://t37.net/nginx-optimization-understandingsendfile-tcp_nodelay-and-tcp_nopush.html>[Consulta: 2 de Junio de 2015] [40] Virtualmin, Inc. Open Source Web Hosting and Cloud Control Panels | Virtualmin. <http://www.virtualmin.com/>[Consulta: 27 de Marzo de 2015] [41] W3C Consortium. CGI - Common Gateway Interface. <http://www.w3.org/CGI/>[Consulta: 26 de Marzo de 2015] [42] W3SCHOOLS.IN. What is HTML. <http://www.w3schools.in/html/intro/>[Consulta: 28 de Marzo de 2015] [43] Webmin wiki Page. Webmin Module Development. <http://doxfer.webmin.com/Webmin/Module_Development>[Consulta: 27 de Mayo de 2015] [44] Wessels, Duane (2001). Web caching. Beijing: O'Reilly 65 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 66 Anexos Anexo 1: Análisis estadístico Con el fin de encontrar unos parámetros de configuración mas óptimos para NGINX, se ha diseñado una aplicación de consola en Java que analice el tamaño de los objetos que conforman las webs que lee como entrada desde un fichero de texto llamado Webs.txt. Para cada una de estas 15 webs que conforman la población de estudio, la aplicación se encargaba de realizar peticiones HTTP —como si de un navegador se tratase— a todos los objetos enlazados en la primera página de cada uno de los sitios, almacenando para cada petición el tamaño de la respuesta. Estas webs fueron elegidas en función del propósito de la misma, desde webs gubernamentales, centros educativos o blogs, hasta medios de información digitales. La lista de sitios de los que se realizó el estudio es la siguiente: •http://www.upv.es – Web de la Universidad Politécnica de Valencia. •http://www.uclm.es – Web de la Universidad de Castilla-La Mancha •http://www.ugr.es/ – Web de la Universidad de Granada. •http://www.aemet.es/es/portada – Web de la Agencia Española de Meteorología. •http://www.csic.es/ – Web del Centro Superior de Investigaciones Científicas. •http://www.europarl.europa.eu/portal/es – Web del Parlamento Europeo. •http://www.eldiario.es/ – Web del periódico digital eldiario.es. •http://www.lemonde.fr – Web del periódico digital francés LEMONDE. •http://rt.com/ – Web del canal de noticias de la Federación de Rusia. •http://nginx.com/ – Web del software NGINX. •http://www.w3schools.com/ – Web de educación del consorcio World Wide Web. •http://www.debian.org/ – Web del sistema operativo de código abierto Debian. •http://www.securityartwork.es/ – Blog de seguridad TI de la empresa S2 Grupo. •http://securityblog.redhat.com/ – Blog de seguridad TI de los desarrolladores de RedHat Enterprise Linux. •http://www.omicrono.com/ – Blog de tecnología. Basándonos en los resultados de este análisis estadístico para todos los objetos analizados (en total 1511), obtuvimos la proporción de todos los recursos que se encontraban dentro de cada rango de tamaños: 67 Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Tamaño Porcentaje Acumulado Hasta 4kB 0.19258769 0.19258769 De 4kB a 8kB 0.07478491 0.2673726 De 8kB a 16kB 0.112508275 0.37988088 De 16kB a 32kB 0.13765718 0.5175381 De 32kB a 64kB 0.22964925 0.7471873 De 64kB a 128kB 0.22964925 0.9768365 Mas de 128kB 0.023163468 1.0 Como se puede apreciar en la tabla de resultados anterior, la mayoría de los objetos que contienen las webs analizadas tienen un tamaño mayor de 16kB, aproximadamente el 60% de ellas, por lo que éste ha sido un dato importante en las configuraciones que siguen. Así, el código Java que ha sido desarrollado para permitir el análisis anterior es el siguiente: Clase Main.java En primer lugar, la clase main.java se encarga de leer el fichero de texto llamado webs.txt que contiene las URL de los sitios web señalados anteriormente, almacenandolos en una lista. Una vez leido, se lanzan tantos hilos simultaneos de tipo DescargaWeb como indique la variable numPetPa –por defecto 7-- para descargar todo el contenido enlazado en la primera página de los sitios web (el contenido de la misma es examinado por DescargaWeb). Estas conexiones almacenan todos los datos en la lista llamada resultados para su posterior análisis estadístico, cuyos resultados serán almacenados en un fichero de texto. 68 import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; public class Main { private static List<String> listawebs; static List<Peticion> resultados; static int numPetPa=7; //Leemos el fichero que contiene las webs a analizar private static void leeWebs () { BufferedReader lector; 69 File f; String linea=""; FileReader fRead; listawebs=new ArrayList<String>(); try { f=new File("webs.txt"); fRead = new FileReader(f); lector=new BufferedReader(fRead); while ( (linea=lector.readLine())!=null ){ listawebs.add(linea); // Realiza tantas peticiones como enlaces tiene la web } lector.close(); fRead.close(); } catch (Exception e) { System.out.println("leeWebs - Error al leer el fichero"+ e); e.printStackTrace(); } } private static void escribeRes () { FileWriter fRes; PrintWriter escritor; Peticion res; int n4k=0, n8k=0, n16k=0, n32k=0, n64k=0, n128k=0, nmas128k=0; float hasta4k=0, hasta8k=0, hasta16k=0, hasta32k=0, hasta64k=0, hasta128k=0, masde128k=0; int suma=0, maximo=0, talla=0; try { fRes = new FileWriter("Resultados.txt"); escritor=new PrintWriter(fRes); for ( int n=0; n<resultados.size(); n++ ){ res=resultados.get(n); talla=res.getSize(); if ( talla>maximo ) maximo=talla; if ( talla<=4096 ) n4k++; if ( talla>4096 && talla<=8192 ) n8k++; if ( talla>8192 && talla<=16384 ) n16k++; if ( talla>16384 && talla<=32768 ) n32k++; if ( talla>32768 && talla<=65536 ) n64k++; if ( talla>65536 && talla<=65536*2 ) n128k++; if ( talla>65536*2 ) nmas128k++; suma+=talla; //escritor.println(res.getName()+" -- "+talla); } hasta4k=((float)n4k/resultados.size()); hasta8k=((float)n8k/resultados.size()); hasta16k=((float)n16k/resultados.size()); hasta32k=((float)n32k/resultados.size()); hasta64k=((float)n64k/resultados.size()); Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 70 hasta128k=((float)n128k/resultados.size()); escritor.println("Objetos TOTALES="+resultados.size()); escritor.println("MEDIA -> "+ (suma/resultados.size())); escritor.println("MAXIMO -> "+maximo); escritor.println("Hasta 4k="+hasta4k+" - Acumulado="+hasta4k); escritor.println("De 4k a 8k -> "+hasta8k+" - Acumulado="+((float)(n8k+n4k)/resultados.size())); escritor.println("De 8k a 16k -> "+hasta16k+" - Acumulado="+((float)(n8k+n4k+n16k)/resultados.size())); escritor.println("De 16k a 32k -> "+hasta32k+" - Acumulado="+((float)(n32k+n8k+n4k+n16k)/resultados.size())); escritor.println("De 32k a 64k -> "+hasta64k+" - Acumulado="+((float)(n64k+n32k+n8k+n4k+n16k)/resultados.size())); escritor.println("De 64k a 128k -> "+hasta128k+" - Acumulado="+((float) (n128k+n64k+n32k+n8k+n4k+n16k)/resultados.size())); escritor.println("Mas de 128k -> "+masde128k+" - Acumulado="+((float) (nmas128k+n128k+n64k+n32k+n8k+n4k+n16k)/resultados.size())); escritor.close(); fRes.close(); } catch (IOException e) { e.printStackTrace(); } } private static void lanzaPeticiones () { DescargaWeb pet=null; DescargaWeb []peticiones=new DescargaWeb[numPetPa]; int n=0, k=0; for ( n=0, k=0; n<listawebs.size(); n++, k++){ if ( k==numPetPa ){ for ( k=k-1; k>=0; k--){ try { peticiones[k].join(); //Esperamos a que terminen las webs de descargarse } catch (InterruptedException e) { e.printStackTrace(); } } } else { pet=new DescargaWeb(listawebs.get(n)); pet.start(); // Lanzamos las webs de forma paralela maximo numPetPa peticiones[k]=pet; } } for ( k=k-1; k>=0; k--){ try { Clase main.java Clase DescargaWeb.java DescargaWeb.java es la clase encargada de crear objetos de tipo TCPCon para descargar los recursos que contienen cada una de las paginas leídas del fichero. Para ello, en primer lugar descarga la pagina principal de las webs y analiza su codigo en busca del contenido enlazado en el mismo, almacenando las direcciones en una lista. Posteriormente, realiza conexiones simultaneas (TCPCon) para descargar todos los objetos enlazados encontrados de 5 en 5 y espera a que terminen para lanzar otras nuevas. 71 import java.util.ArrayList; import java.util.Hashtable; import java.util.List; public class DescargaWeb extends Thread { TCPCon conexion=null; Hashtable<String,String> hash=new Hashtable<String,String>(); List<String> lista; String servidor=""; public DescargaWeb (String url) { conexion=new TCPCon(url); servidor=conexion.host; } public void run () { int k=0, talla=0, n=0; conexion.start(); // Lanzamos la peticion para index examinaCodigo(); // Examinamos el codigo de index para extraer los enlaces talla=lista.size(); TCPCon hilos[]=new TCPCon[5]; System.out.println("Hay "+lista.size()+" elementos en "+servidor); for( n=0, k=0; n<talla; n++,k++ ) { // Realizamos peticiones para todos los enlaces if (k==5){ peticiones[k].join(); //Esperamos a que terminen las webs restantes } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { resultados=new ArrayList<Peticion>(); leeWebs(); lanzaPeticiones(); if ( resultados.size()>0 ) escribeRes(); System.out.println("Fin del programa"); return; } } Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web 72 System.out.println("Lanzados 5 Threads para "+servidor); for ( k=0; k<5; k++){ //Esperamos a que los 5 hilos hayan acabado try { hilos[k].join(); } catch (InterruptedException e) { e.printStackTrace(); } } k=-1; // Ponemos a 0 el contador de hilos lanzados } else { //lanzamos hilos mientras no llevemos 5 hilos[k]=new TCPCon(lista.get(n).toString(), false); hilos[k].start(); //Lanzamos 5 hilos } } System.out.println("Lanzados "+k+" Threads para "+servidor); for (int t=0 ; t<k; t++){ //Esperamos a los que hayan quedado lanzados al final pero no sean 5 justos try { hilos[t].join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Lanzados todos los Threads para "+servidor); } // Obtiene las url de cod coincidentes con el el contenido de busca private void dirObjetos(String cod, String busca) { String aux2 = "", ruta = ""; String objeto = "", enlace = ""; while (true) { if (cod.indexOf(busca) < 0) { break; } cod = cod.substring(cod.indexOf(busca) + busca.length(), cod.length()); if ( cod.startsWith("https://")) continue; aux2 = cod.substring(0, cod.indexOf("\"")); // Extraemos enlace a enlace aux2=aux2.replace("#",""); if ( aux2.contains("instagram") ) continue; if (aux2.startsWith("http://")) { // No hace falta cambiar el enlace ruta=aux2; } else { // Hay que añadirle http y el servidor en el que esta if ( aux2.startsWith("/") ) objeto=aux2; else objeto = "/" + aux2; ruta = "http://"+servidor+objeto; } //Almacenamos en una lista los pares de direccion y lo que se necesita if ( hash.get(ruta)==null ){ hash.put(ruta,""); lista.add(ruta); } cod = cod.substring(cod.indexOf("\"")+1); } Clase DescargaWeb.java Clase TCPCon.java Por otro lado, la clase TCPCon.java realiza las conexiones al servidor, descarga los recursos y calcula su tamaño. Además, almacena en una lista de objetos de la clase Peticion toda esta información para su posterior análisis estadístico en la clase Main.java. 73 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.Socket; import java.util.List; import javax.sound.sampled.AudioFormat; public class TCPCon extends Thread { Socket con; BufferedInputStream leeSock; PrintWriter escSock; int port; String url=""; String host; //host que alberga el objeto String objeto; //objeto int tamCabecera=0, tamBody=0, tamTotal=0; String res=""; boolean quieroCodigo=false, disponible=false, espera=false; public TCPCon(String host, int puerto, String loc) { port = puerto; this.host = host; this.objeto = "/"; } public TCPCon(String host, int puerto, String dir, String loc) { port = puerto; this.host = host; this.objeto = dir; } public void examinaCodigo() { try { conexion.join(); } catch (InterruptedException e) { System.out.println("fallo en la espera"); e.printStackTrace(); } lista=new ArrayList<String>(); String codigo=conexion.getRes(); dirObjetos(codigo, "src=\""); dirObjetos(codigo, "SRC=\""); dirObjetos(codigo, "rel=\"stylesheet\" href=\""); dirObjetos(codigo, "REL=\"stylesheet\" HREF=\""); dirObjetos(codigo, "href=\""); dirObjetos(codigo, "HREF=\""); hash.clear(); } } Integración de un proxy inverso NGINX con un panel de control Virtualmin para crear una plataforma de servicios de hospedaje Web Cabe destacar que en caso de que no se desee indicar la clave cada vez que el servicio que hace uso del certificado lo requiere, es posible realizar la firma del certificado despues de generar el fichero que contenga la clave privada descifrada. Esto se realiza ejecutando el siguiente comando: openssl rsa -in sslcifrado.key -out ssl.key Una vez obtenidos tanto el certificado como la clave, basta con mover los ficheros al directorio raiz del servidor virtual para el que se generan —por defecto /home/nombreservidor/— y reiniciar NGINX. 80 81