Universidad Politécnica de Cartagena Escuela Técnica Superior de Ingeniería de Telecomunicación PRÁCTICAS DE APLICACIONES EN INTERNET Práctica 1: SERVIDOR HTTP. APACHE 2 Profesores: Esteban Egea López Ángel Pintado Sedano 1 1. OBJETIVOS • • Comprender el funcionamiento de un servidor HTTP. Comprender cómo se organizan los documentos en un servidor web. 2. INTRODUCCIÓN Un servidor HTTP o servidor web es una aplicación que se encarga de servir contenidos usando el protocolo HTTP (Hyper Text Mark-up Language). El servidor acepta peticiones del cliente y devuelve los documentos HTML apropiados. Hay, además, una serie de tecnologías complementarias que se encargan de aumentar la capacidad del servidor más allá de su habilidad para entregar páginas HTML estándar, como son CGI (Common Gate Interface), SSI (Server Side Includes) o PHP (Hypertext Preprocessor), permitiendo dotar de contenido dinámico a los documentos HTML. El servidor Apache (http://www.apache.org) ha sido el servidor web más popular desde 1996, actualmente se utiliza en más del 50% de los sitios web en Internet. Es una aplicación software de libre distribución que implementa un servidor HTTP, disponible para varios sistemas operativos, fundamentalmente UNIX, aunque hay versiones para Windows. El código fuente está disponible. Simplificadamente, Apache es un proceso que se ejecuta en un entorno UNIX. Es un "demonio" que se ejecuta en segundo plano y está continuamente escuchando el puerto 80, en su configuración por defecto, esperando a atender peticiones HTTP. 2.1 Módulos y multiprocesamiento Apache está diseñado para ser un servidor web potente y flexible que pueda funcionar en la más amplia variedad de plataformas y entornos. Las diferencias entre plataformas y entornos hacen que a menudo sean necesarias diferentes características o funcionalidades, o que una misma característica o funcionalidad sea implementada de diferente manera para obtener una mayor eficiencia. Apache utiliza un diseño modular. Este diseño permite a los administradores de sitios web elegir qué características van a ser incluidas en el servidor seleccionando que módulos se van a cargar, ya sea al compilar o al ejecutar el servidor. Apache 2.0 extiende este diseño modular hasta las funciones más básicas de un servidor web. El servidor viene con una serie de Módulos de MultiProcesamiento o MPM que son responsables de escuchar los puertos de red de la máquina, aceptar las peticiones, y generar los procesos hijo que se encargan de servirlas. La extensión del diseño modular a este nivel del servidor ofrece dos beneficios importantes: • Apache puede soportar de una forma más fácil y eficiente una amplia variedad de sistemas operativos. En concreto, la versión de Windows de Apache es mucho más eficiente, porque el módulo mpm_winnt puede usar funcionalidades nativas de red en lugar de usar la capa POSIX como hace 2 Apache 1.3. Este beneficio se extiende también a otros sistemas operativos que implementan sus respectivos MPMs. • El servidor puede personalizarse mejor para las necesidades de cada sitio web. Por ejemplo, los sitios web que necesitan más que nada escalabilidad pueden usar un MPM basado en threads como worker, mientras que los sitios web que requieran por encima de otras cosas estabilidad o compatibilidad con software antiguo pueden usar prefork. A nivel de usuario, los MPMs son como cualquier otro módulo de Apache. La diferencia más importante es que solo un MPM puede estar cargado en el servidor en un determinado momento. Hay varios módulos MPM disponibles, algunos son específicos de la plataforma, nos centraremos en dos de los disponibles para UNIX: • worker: implementa un servidor híbrido multi-proceso multi-hilo. Mediante el uso de threads para atender las solicitudes, es capaz de servir a un gran número de peticiones con menos recursos del sistema que un servidor basado en procesos. Sin embargo, conserva gran parte de la estabilidad de un servidor basado en procesos manteniendo múltiples procesos disponibles, cada uno con muchos hilos. • event: una variante del anterior que permite delegar ciertas tareas de procesado comunes a hilos de soporte, liberando los hilos principales para atender nuevas peticiones. De esta manera se aumenta la escalabilidad. • prefork: es el servidor clásico, basado en múltiple procesos. Es menos eficiente pero más estable que los anteriores. No utiliza hilos (threads) lo que permite que se pueda usar con librerías que no los soportan. Además, al aislar las peticiones, evita que un problema en un hilo afecte a los demás. En las prácticas usaremos el módulo MPM event, que es el que se instala por defecto. El funcionamiento es el siguiente: cuando se ejecuta Apache, se crea un proceso padre, de control, que atiende peticiones al puerto 80. Este lanza varios procesos hijos (fork()) que se encargan de escuchar en ese mismo puerto y atender peticiones. Cada hijo crea un número fijo de threads responsables de atender las peticiones, además de un thread que se encarga de escuchar y gestionar las conexiones. Este es el funcionamiento del módulo worker en particular. El funcionamiento de event es una variante que resuelve ciertos problemas específicos de Apache. Se puede consultar su funcionamiento en detalle en la documentación de Apache. El funcionamiento de los módulos y las reglas que tienen que aplicar a las peticiones vienen determinados por unas directivas que se incluyen en los ficheros de configuración. Estas directivas determinan, entre otras cosas, los directorios en los que se encuentran los documentos que van a ser servidos, el control de acceso que se le aplicará a las peticiones, etc. Es conveniente conocer el usuario bajo el cual se ejecutan los procesos y los privilegios que tiene. El proceso padre se ejecuta como root puesto que se tiene que unir (bind) al puerto 80, que es un puerto privilegiado en UNIX. Sin embargo, los procesos hijos se ejecutan bajo un usuario menos privilegiado (normalmente el usuario www-data), para evitar que un proceso con privilegios de root atienda peticiones que llegan a través de la red. 3 Las directivas del fichero de configuración establecen los privilegios de los usuarios hijos de Apache. De esta manera, el proceso padre cuando crea los hijos les asigna el usuario www-data, el cual prácticamente no tiene privilegios sobre los recursos del sistema. Los procesos hijos tienen que tener permiso para leer los contenidos que se van a servir pero ninguno más aparte de estos. Los privilegios que establecen las anteriormente mencionadas directivas son también los que heredarán los scripts CGI, así como las llamadas al sistema y a los recursos que utilice el código de los scripts, es decir, se ejecutarán con muy pocos privilegios. 2.2 Procesado de las peticiones El servidor atiende las peticiones HTTP que le llegan al puerto que escucha, el puerto 80 por defecto. Las peticiones se realizan mediante el protocolo HTTP. Es decir, el cliente le envía al servidor un mensaje (este mensaje llega encapsulado en un paquete TCP/IP que el SO desencapsula y le pasa al proceso que escucha el puerto correspondiente) del tipo : GET /index.html HTTP/1.1 Este mensaje le indica al servidor (en realidad, uno de los procesos “hijo”) que le solicitan el documento index.html que se encuentra en el directorio raíz de los documentos. El directorio raíz es el lugar en el que se encuentran los documentos HTML que puede servir el sitio. En él se encuentra el árbol de directorios con documentos disponibles. La cadena de la petición que aparece tras el método GET, en este ejemplo /index.html,se denomina ruta local. El servido concatena la ruta del directorio raíz con la ruta local para obtener la ruta absoluta del documento. Ruta absoluta = ruta del raíz + ruta local El directorio raíz puede ser cualquier directorio de la máquina sobre la que se ejecuta Apache. En el fichero de configuración hay una directiva (DocumentRoot) que indica este directorio. Por ejemplo, si el valor de esta directiva es /usr/doc/htdocs, el proceso servidor creará una ruta (path) absoluta igual a /usr/doc/htdocs/index.html. Si este documento se encuentra en este directorio, y el proceso servidor tiene permisos para leerlo, lo devolverá al cliente, con lo que habrá completado la petición. En caso contrario devolverá un mensaje de error. De aquí se deduce que una petición del tipo www.midominio.com/index.html significa que se le está pidiendo al sitio el documento index.html que se encuentra en el directorio raíz. Mientras que una petición del tipo www.midominio.com/usuario/index.html, le solicita el documento index.html que se encuentra en el directorio usuario, que a su vez estará bajo el raíz. 4 Toda la información relativa al servidor Apache se puede encontrar en: http://httpd.apache.org/docs/ 3. DESARROLLO DE LA PRÁCTICA 3.1 Configuración del servidor En la práctica, la mayoría de las distribuciones de Linux incluyen Apache y lo instalan junto con el resto del sistema operativo. La diferencia entre distribuciones es la ruta dónde se instalan los archivos. Por ejemplo, en Ubuntu/Debian, los archivos de configuración se guardan en el directorio /etc/apache2/. En la práctica utilizaremos la instalación de Apache que proporciona Kubuntu. Una vez instalado el servidor, hay que configurar su funcionamiento. Apache se configura mediante múltiples ficheros de texto. Estos ficheros incluyen órdenes, llamadas directivas, que especifican el modo de funcionamiento del servidor. Cada directiva especifica el funcionamiento de una característica del servidor. Cada directiva tiene a su vez una serie de opciones. El servidor, al iniciarse, lee la configuración, establece su modo de funcionamiento de acuerdo y espera a que le lleguen peticiones. Los ficheros de configuración sólo son leídos al iniciar el servidor, por ello, si se modifica alguna directiva, hay que parar el servidor y volver a reiniciarlo para que surtan efecto las modificaciones. Los ficheros de configuración se encuentran en el directorio /etc/apache2/. Estos ficheros contienen la configuración por defecto del servidor. 3.2 Ejecución del servidor El servidor al ser instalado viene con una configuración por defecto que nos permite probarlo directamente. Para ejecutar el servidor normalmente se recurre a un script de inicio. En Kubuntu se ejecuta como un servicio estándar, con systemctl {start|stop|restart…} apache2 es decir, se ejecuta el servicio con un parámetro para arrancar, parar, reiniciar u otros • Pare el servidor. Ejecute el siguiente comando: systemctl stop apache2 Para ejecutar el servidor: systemctl start apache2 • Ejecute el servidor. Ahora el servidor ya está corriendo. • Compruebe que todo funciona correctamente. Para ello abra un navegador web y solicite la URL http://localhost. ¿Por qué ha solicitado esta URL en particular? Indique otra URL equivalente 5 • Compruebe los procesos que se están ejecutando. Para ello ejecute ps aux | grep apache2. Examine los procesos que se están ejecutando y el usuario que los ejecuta y explique lo que observa. • Para reiniciar el servidor (cuando está corriendo) use systemctl restart apache2. 3.3 Ficheros de configuración y configuración global. El servidor se configura a través de archivos de texto simple. Estos archivos pueden estar ubicados en diversos lugares, dependiendo de cómo se ha instalado el servidor. La configuración se divide normalmente en varios archivos más pequeños, para la facilitar la gestión. Estos archivos se cargan a través de la directiva Include. El servidor se configura mediante el establecimiento de directivas de configuración en estos ficheros de configuración. Una directiva es una palabra clave seguida de uno o más argumentos que establecen su valor. Los ficheros de configuración suelen incluir una amplia descripción de cada directiva, lo cual le será muy útil. Además de directivas, aparecen los contenedores. Estos se diferencian de las directivas en que aparecen entre los caracteres <>. Un contenedor sirve para definir un contexto de aplicación de las directivas. Por ejemplo, el contenedor <Directory “/var/www/user”> indica que todos las directivas que aparecen entre el inicio y el final (</Directory>) se aplican sólo a ese directorio. En la dirección http://httpd.apache.org/docs/2.4/mod/quickreference.html encontrará una lista de las directivas de Apache. Allí se incluye una descripción de las mismas, así como de las opciones que se le pueden aplicar y del contexto en el que se usan. La sintaxis es muy importante, así que utilice la dirección anterior para comprobar que ha escrito correctamente una directiva si tiene dudas. Los espacios en blanco, así como los saltos de línea y los retornos de carro no son tenidos en cuenta, por lo que puede usarlos para mejorar la legibilidad cuando modifique el fichero. En las distribuciones Ubuntu/Debian la configuración se guarda en /etc/apache2. • Examine el directorio de configuración de Apache. El fichero principal de configuración se llama apache2.conf y contiene opciones globales de configuración. Además se encarga de cargar el resto de ficheros de configuración mediante directivas Include. Como dijimos anteriormente, Apache se desarrolla de forma modular, por tanto, la configuración se ha dividido en módulos, es decir, cada módulo aporta su propio fichero de configuración. Además, un servidor puede servir múltiples sitios simultáneamente, es lo que se llaman virtual hosts. Esto quiere decir que un mismo servidor puede servir diferentes nombres de dominio, como www.ssd.upct.es y www.ai.upct.es. 6 Entonces, el enfoque usado para la configuración es tener dos tipos de directorios: 1. Los directorios mods-available y sites-available, contienen los ficheros de configuración de los módulos y sitios virtuales disponibles. Son módulos que se han compilado y por tanto están disponibles para su uso, pero no están en uso. 2. Los directorios mods-enabled y sites-enabled, incluyen los ficheros de configuración de los módulos que realmente se cargan y se ejecutan en el servidor. La idea es que para cargar/activar un módulo simplemente hay que copiar el fichero de configuración de mods-available a mods-enabled. Y para desactivarlo hay que borrarlo de mods-enabled. ATENCION: En vez de copiar y borrar directamente, la distribución proporciona comandos para habilitar o deshabilitar módulos: a2enmod y a2dismod permite deshabilitar y habilitar un módulo de apache. Utilice este método. En realidad, cada módulo tiene asociado un fichero de carga: modulo.load y un fichero de configuración: modulo.conf. El primero simplemente fuerza a Apache a que cargue el módulo y el segundo establece la configuración. Hay que copiar ambos para activar un módulo. • Examine los cuatro directorios, available y enabled, observando y abriendo algunos de los ficheros que encuentre en ellos. 3.4 Servidor principal El concepto de servidor principal aparece porque Apache permite definir directorios virtuales, es decir, permite que el mismo servidor atienda peticiones dirigidas a diferentes direcciones IP (en la misma máquina, por ejemplo si tienes varios interfaces de red) o permite que un mismo sitio (definido por una única dirección IP) pueda tener asignados diferentes nombres de dominio, atendidos por el mismo servidor. Es decir, en el DNS se ha establecido la misma IP para diferentes dominios. Los servidores virtuales vienen definidos por el contenedor <VirtualHost>. En esta práctica no se estudiarán directorios virtuales. Veamos las directivas disponibles. Primero algunas opciones de configuración global se establecen en ports.conf. Listen. Indica el puerto que se servirá. Se dejará el puerto por defecto, el 80. Otra de las opciones es la del directorio raíz (DocumentRoot) que se establece en 000default.conf dentro del directorio mods-enabled: DocumentRoot. Indica el directorio raíz a partir del cual se servirán documentos. Por defecto es /var/www/html. Hay que tener en cuenta que cualquier petición a un documento que no esté bajo este directorio no se servirá. • ¿Cuál es el raíz de los documentos? 7 • Cree un par de documentos HTML y cópielos a diversos directorios bajo el raíz de los documentos. Compruebe que los puede obtener con el navegador. • Asigne permisos 740 a los documentos HTML e intente obtenerlos. Explique lo que pasa. Mientras que el resto se establecen en sites-enabled/000-default. • • Configure el servidor para que escuche el puerto 5050. Observe que tiene que modificar dos ficheros para cambiar el puerto. Reinicie el servidor y compruebe mediante su navegador este funcionamiento. ¿Qué URL ha utilizado? Vuelva a asignar el puerto 80. La mayoría de directivas aparecen dentro de contenedores, como hemos dicho. <Directory dir> delimita el directorio para el cual se aplicarán las directivas. Permite aplicar directivas y controles de acceso basados en directorios, por ejemplo, quién y cómo se puede acceder a un determinado directorio. El primer contenedor que aparece en apache.conf es <Directory />. Establece las directivas que se aplicarán a todos los subdirectorios a partir de la raíz del sistema (no confundir con la raíz de los documentos que serán servidor por el servidor Apache). Esto sirve para aplicar condiciones de acceso y funcionamiento muy restrictivas que luego serán sobreescritas caso a caso. Así tendremos el comportamiento del servidor controlado para cualquier directorio al que se intente acceder. El siguiente contendor es <Directory “/var/www”>. Con las directivas aquí incluidas se sobreescriben las que el contenedor <Directory /> establecía. Así, mientras que el primero sólo permite para cualquier directorio la opción FollowSimLinks, este nuevo contenedor añade más opciones como son Indexes y MultiViews. Diríjase a la documentación de Apache y de las directivas para saber en qué consisten esas opciones. • • • • Copie cualquier página web a su directorio raíz. Elimine el fichero index.html del directorio raíz. Elimine la opción Indexes de /var/www/html y reinicie el servidor. Solicite mediante su navegador la raíz de los documentos (http://localhost). ¿Qué ocurre? Añada de nuevo la opción Indexes y vuelva a solicitar la raíz, ¿Qué ocurre en este caso? Sigamos con las directivas. Veamos algunos de los módulos que configuran la forma en que se sirven las peticiones. En dir.conf puede encontrar: DirectoryIndex. Esta directiva aparece dentro de un contenedor <IfModule mod_dir.c >. Es decir, se aplica si se ha cargado ese módulo. Permite indicar el nombre de la página HTML que aparecerá como índice por defecto, en orden de preferencia de derecha a izquierda. DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm 8 • Cree 2 páginas HMTL diferentes y guárdelas como index.html e index.htm y solicite http://localhost Dentro del módulo alias.conf puede encontrar: Alias. Esta directiva también aparece dentro del contenedor <IfModule alias_module>. Sirve para indicar que ciertos directorios contienen documentos para ser servidos aunque no aparezcan dentro del directorio raíz (el especificado por DocumentRoot). Por ejemplo, la directiva Alias /icons/ “/usr/local/web/apache/icons” está diciendo cuando haya peticiones al directorio /icons los documentos sean buscados en /usr/local/web/apache/icons. Entonces, si no hubiera un Alias, la petición www.midominio.com/icons/foto.gif provocaría que el servidor buscara un fichero llamado foto.gif en el directorio /var/www/icons, es decir, bajo el raíz. Como sí que hay un alias, el fichero se busca en /usr/local/web/apache/icons. Después de esta directiva aparece un contenedor correspondiente al directorio nombrado en la directiva que establece el control de acceso y la configuración de ese directorio. . 3.5 Documentos de usuario En el apartado anterior acaba de comprobar que los documentos que puede servir Apache deben estar en el directorio raíz que se indique en la directiva DocumentRoot. Esta forma de organizar los documentos es adecuada para un sitio web en el que hay un solo administrador que se encarga de publicar los contenidos. El problema es que deja de ser práctico cuando hay muchos usuarios que necesitan publicar documentos. Piense en la Universidad, por ejemplo, si cada profesor quiere publicar contenidos de su asignatura, tendría que enviárselos al administrador de la web para que los colocara y organizara en directorios bajo el raíz. ¡Y hay más de 500 profesores en la UPCT!. Además tendría que actualizarlos cada cierto tiempo, etc. Para solucionar este problema el usuario debe ser capaz de poder publicar y organizar los documentos visibles en la web sin necesidad del administrador. La solución es simple: cada usuario tiene asignado un directorio en el que puede colocar documentos que serán servidos, aunque no se encuentren bajo el DocumentRoot. Apache permite designar estos directorios mediante la directiva UserDir cuyo valor es public_html, que se encuentra en el módulo userdir.conf. Cuando al servidor le lleguen peticiones del tipo www.midominio.com/~usuario/index.html, el servidor buscará dentro del directorio personal del usuario /home/usuario/public_html el archivo solicitado. Es decir, cuando en la URL de la petición a continuación del dominio aparezca el símbolo ~ seguido de un nombre de usuario que exista en el sistema, el servidor buscará el documento pedido bajo el directorio public_html del usuario. Ejemplos: 9 www.ait.upct.es/~eegea/productos.html devolverá el fichero productos.html que se encuentra en /home/eegea/public_html. www.ait.upct.es/~jvales/imagenes/foto.jpg devolverá el fichero foto.jpg que se encuentra en el directorio /home/jvales/public_html/imagenes. • • • Cree un usuario (con el comando adduser). Compruebe que está habilitado el módulo userdir y habilítelo en su caso. Coloque documentos HTML en el public_html del usuario y compruebe que puede visualizarlos con el navegador. A veces, principalmente por imagen y organización, no se quiere utilizar la notación ~usuario. Para ello puede utilizar un alias. • Utilice un Alias para que las peticiones que se realicen al directorio admin, se sirvan mediante los documentos del usuario que ha creado. Es decir, cuando se solicite http://localhost/admin/ se servirá el index.html que se encuentra en el public_html del usuario que ha creado. 3.6 Ficheros de registro En este fichero se registra cualquier error que se produce en el servidor. Este fichero se utiliza principalmente para depurar los scripts que colgamos en el sitio web. Si tiene que programar scripts CGI o PHP, el fichero error.log es fundamental puesto que cualquier mensaje de error que produzca el script se almacena en ese fichero. Apache proporciona varias directivas para configurar estos ficheros. Los ficheros de registro son muy importantes también a la hora de administrar el servidor. El fichero access.log registra todos los accesos al servidor por lo que resulta muy útil para obtener estadísticas procesándolo adecuadamente. • Examine el contenido de los ficheros access.log y error.log. Para ello, determine previamente dónde se encuentran. 3.7 Peticiones y respuestas Finalmente examinaremos en detalle la encapsulación de HTTP y las conexiones que realiza. Para ello: • Abra wireshark y capture su interfaz. Alternativamente, si no dispone de wireshark, utilice las herramientas de desarrollo de su navegador para examinar las peticiones de red. • Realice mediante el navegador una petición a http://localhost. Examine mediante wireshark la petición. Describa el encapsulamiento. Describa la parte del nivel de aplicación de la petición y la respuesta del servidor. • Modifique la página index.html que creó previamente para que incluya la siguiente imagen <img src=” https://www.upct.es/imagenes/estructura/logo_upct.png”> • Elimine la captura y vuelva a comenzar. • Solicite ahora la página index.html. Compruebe cuantas conexiones TCP se establecen con su servidor. ¿Cuántas conexiones TCP se establecen en total? ¿Por qué? 10 • • • Busque una imagen descárguela y añádala a la página de manera que se sirva desde su servidor. De nuevo solicite la página y capture el intercambio con wireshark. ¿Cuántas conexiones TCP se establecen ahora? Finalmente, recargue la página y examine la respuesta que le da el servidor. ¿Qué código ha recibido? ¿Qué significa? 11