Objetivo
Nuestro objetivo es configurar Apache httpd para que funcione como un proxy frente al contenedor de la aplicación Apache Tomcat.
Sistema operativo y versiones de software
- Sistema operativo: Red Hat Enterprise Linux 7.5
- Software: Apache httpd, Apache Tomcat
Requisitos
Acceso privilegiado al sistema
Dificultad
FÁCIL
Convenios
- # – requiere que los comandos de Linux dados se ejecuten con privilegios de root, ya sea directamente como usuario root o mediante el uso de
sudo
comando - $ – comandos de Linux dados para ser ejecutados como un usuario regular sin privilegios
Introducción
El uso de Apache httpd como proxy para un contenedor de aplicaciones Apache Tomcat es una configuración común. Viene con muchos casos de uso, el más trivial es servir contenido estático desde httpd
, al mismo tiempo que proporciona servicios que implementan una lógica de negocios pesada desde una aplicación escrita en Java que reside en el contenedor Tomcat.
Al crear un proxy, podemos crear una especie de front-end para la capa de la aplicación, donde podemos introducir medidas de seguridad en el servidor web, aplicar balanceo de carga, usar redirección condicional o usar cualquier otra funcionalidad provista por el servidor web. De esta manera, no necesitamos implementar ninguna de estas características en nuestra aplicación y podemos enfocar sus capacidades al servicio en sí. Tendremos un servidor web con todas las funciones presentado para los usuarios, algunas de las direcciones URL se reenviarán silenciosamente al contenedor de la aplicación al que es posible que no se pueda acceder por sí mismo. Las respuestas de la aplicación se reenvían a los clientes, quienes no sabrán que hablaron con otra cosa que no sea el servidor web, es decir, si tenemos cuidado de no exponer ninguna información (como mensajes de error no manejados) de la aplicación que pueda hacerles adivinar que hay más. de una capa.
Usaremos el protocolo AJP que se puede usar entre servidores web y contenedores de aplicaciones basados en Java para proporcionar la capacidad de equilibrar la carga entre varios servidores de aplicaciones; sin embargo, configurar un equilibrador de carga está fuera del alcance de este tutorial.
Configuraremos nuestra configuración en Red Hat Linux 7.5, pero el servidor web Apache, el módulo AJP y el contenedor de la aplicación Apache Tomcat están disponibles en todas partes y, por lo tanto, esta configuración es portátil con pequeños ajustes como rutas del sistema de archivos o nombres de servicios.
Instalación del software necesario
Primero necesitamos instalar los servicios que usaremos. En una configuración de equilibrio de carga, los servidores Tomcat podrían estar en diferentes máquinas, y a menudo lo están, proporcionando una granja de contenedores que construyen un servicio.
# yum install httpd tomcat tomcat-webapps
Instalamos las tomcat-webapps
con fines de prueba, dentro de este paquete hay una aplicación web de ejemplo implementada en nuestro servidor Tomcat durante la instalación. Usaremos esta aplicación para probar que nuestra configuración funciona según lo previsto.
Ahora podemos habilitar e iniciar nuestro servidor Tomcat:
# systemctl enable tomcat
# systemctl start tomcat
Y nuestro servidor web:
# systemctl enable httpd
# systemctl start httpd
El httpd
predeterminado La instalación contiene los módulos proxy que necesitamos. Para comprobar que es así, podemos consultar el servidor web con apachectl
:
# apachectl -M | grep ajp
proxy_ajp_module (shared)
Nota:las versiones 1.x de Apache usan mod_jk
módulo en lugar de proxy_ajp
.
configuración de httpd
Los ejemplos de aplicaciones web implementadas en Tomcat se publican después de la instalación de forma predeterminada en server-url:8080/examples
. Enviaremos las solicitudes de proxy que lleguen al puerto 80 del servidor (el puerto http predeterminado) solicitando algo de server-url/examples
para ser servido por los examples
Aplicación web implementada en Tomcat. Las solicitudes que lleguen a cualquier otra URL en el servidor serán atendidas por el servidor web. Configuraremos contenido estático para mostrar esta funcionalidad.
En nuestro ejemplo, el servidor se llama ws.foobar.com
. Para que el proxy funcione, cree un archivo de texto con su editor favorito en el directorio de configuración desplegable del servidor web, que es /etc/httpd/conf.d
en sabores de Red Hat, con la extensión de .conf
. Nuestra configuración no necesita que Tomcat sea accesible directamente, por lo que usamos localhost
como host de destino en /etc/httpd/conf.d/example_proxy.conf
archivo:
<VirtualHost ws.foobar.com:80>
ServerName ws.foobar.com
ProxyRequests Off
ProxyPass /examples ajp://localhost:8009/examples
ProxyPassReverse /examples ajp://localhost:8009/examples
</VirtualHost>
Para estar seguros, podemos verificar que nuestra configuración sea correcta antes de aplicar con apachectl
:
# apachectl configtest
Syntax OK
Si la prueba de configuración devuelve un error como el siguiente:
Could not resolve host name ws.foobar.com -- ignoring!
Si significa que nuestro ServerName
La directiva no es válida, ya que no puede ser resuelta por el servidor web. O necesitamos registrarlo en el DNS (local o global), o proporcionar una línea en /etc/hosts
archivo que contiene la dirección IP pública del host seguida del nombre que le dimos en la configuración anterior. Si el archivo de hosts ya contiene la IP con otro nombre (tal vez el nombre de host real), podemos agregar el nombre del servidor después de los nombres de los hosts en la misma línea, la configuración funcionará.
Después de una prueba exitosa, debemos aplicar la nueva configuración reiniciando el servidor web:
# systemctl restart httpd
Configuración de Tomcat
Con la instalación predeterminada, el contenedor Tomcat escuchará las solicitudes AJP en todas las interfaces en el puerto 8009. Esto se puede verificar en el archivo de configuración principal:
# view /usr/share/tomcat/conf/server.xml
[..]
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
[..]
Si no necesitamos que el contenedor Tomcat y las aplicaciones internas sean accesibles por sí mismos, podemos configurar cada conector para escuchar solo en localhost:
Connector address="127.0.0.1" port=..."
Para aplicar podemos reiniciar Tomcat con:
# systemctl restart tomcat
En nuestro laboratorio, la máquina no hará esto, ya que necesitamos ver que recibimos el mismo contenido en ambos puertos 80
y 8080
.
Pruebas
Nuestra configuración mínima de proxy AJP está completa, podemos probarla. Desde la línea de comandos podemos llamar a los examples
aplicación directamente en el puerto 8080
:
$ wget http://ws.foobar.com:8080/examples
--2018-09-13 11:00:58-- http://ws.foobar.com:8080/examples
Resolving ws.foobar.com (ws.foobar.com)... 10.104.1.165
Connecting to ws.foobar.com (ws.foobar.com)|10.104.1.165|:8080... connected.
HTTP request sent, awaiting response... 302 Found
Location: /examples/ [following]
--2018-09-13 11:00:58-- http://ws.foobar.com:8080/examples/
Reusing existing connection to ws.foobar.com:8080.
HTTP request sent, awaiting response... 200 OK
Length: 1253 (1.2K) [text/html]
Saving to: 'examples'
100%[=========================================================================================================================================================================>] 1,253 --.-K/s in 0s
2018-09-13 11:00:58 (102 MB/s) - 'examples' saved [1253/1253]
Y ver los contenidos proporcionados:
$ tail examples
<h3>Apache Tomcat Examples</H3>
<p></p>
<ul>
<li><a href="servlets">Servlets examples</a></li>
<li><a href="jsp">JSP Examples</a></li>
<li><a href="websocket/index.xhtml">WebSocket (JSR356) Examples</a></li>
<li><a href="websocket-deprecated">WebSocket Examples using the deprecated
Apache Tomcat proprietary API</a></li>
</ul>
</body></html>
Y si llamamos a la misma aplicación a través de nuestro proxy AJP, también deberíamos obtener una respuesta, mientras no haya ningún contenido en la raíz del documento del servidor web:
$ wget http://ws.foobar.com/examples
--2018-09-13 11:01:09-- http://ws.foobar.com/examples
Resolving ws.foobar.com (ws.foobar.com)... 10.104.1.165
Connecting to ws.foobar.com (ws.foobar.com)|10.104.1.165|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: /examples/ [following]
--2018-09-13 11:01:09-- http://ws.foobar.com/examples/
Reusing existing connection to ws.foobar.com:80.
HTTP request sent, awaiting response... 200 OK
Length: 1253 (1.2K) [text/html]
Saving to: 'examples.1'
100%[=========================================================================================================================================================================>] 1,253 --.-K/s in 0s
2018-09-13 11:01:09 (101 MB/s) - 'examples.1' saved [1253/1253]
Si todo funciona, obtendremos una respuesta con el mismo contenido, ya que la respuesta final la proporciona la misma aplicación dentro del contenedor:
$ tail examples.1
<h3>Apache Tomcat Examples</h3>
[...]
También podemos probar nuestra configuración con un navegador. Necesitamos llamar a todas las URL con el nombre del servidor como host (al menos el que está en proxy). Para eso, la máquina que ejecuta el navegador debe poder resolver el nombre del servidor, por medio de DNS o un archivo de hosts.
En nuestro entorno de laboratorio, no hemos deshabilitado la escucha de Tomcat en la interfaz pública, por lo que podemos ver lo que se proporciona cuando se le pregunta directamente en el puerto 8080
:
Podemos obtener el mismo contenido a través del proxy AJP proporcionado por el servidor web en el puerto 80
:
Mientras actúa como proxy, httpd
puede servir cualquier otro contenido. Podemos crear contenido estático al que se pueda acceder en alguna otra URL en el mismo servidor:
# mkdir /var/www/html/static_content
# echo "<html><body>Static content</body></html>" > /var/www/html/static_content/static.html
Al apuntar nuestro navegador a este nuevo recurso, se nos proporciona el nuevo contenido estático.
Contenido estático proporcionado por httpdSi no se pudiera acceder al contenedor Tomcat, no sabríamos que la respuesta viene de otro lugar que no sea el servidor web. Como solo utilizamos un proxy para una aplicación específica, no se puede acceder a la aplicación ROOT predeterminada del contenedor a través del proxy, por lo que está oculta para todo más allá del servidor web.
Conclusión
El servidor web Apache es altamente extensible por medio de módulos, uno de ellos es el módulo proxy AJP. La guía anterior utiliza una máquina y expone una aplicación con el proxy, pero el mismo servidor web podría proporcionar una entrada única para muchas aplicaciones, posiblemente en muchos hosts que ejecutan contenedores de aplicaciones, al mismo tiempo que proporciona otro contenido web.
Combinado con otros módulos, como mod_security
, podemos agregar muchas características a nuestro servicio sin necesidad de desarrollarlas dentro de la aplicación, o si surge la necesidad, redirigir el proxy a otro punto final con una sola edición del archivo de configuración y la recarga del servidor web, haciendo una migración o la introducción de la nueva versión de la aplicación en cuestión de segundos. La misma recarga puede llevar al visitante a una página que explica el tiempo de inactividad planificado, mientras se realiza el mantenimiento en los servidores de aplicaciones:los casos de uso de un proxy AJP solo están limitados por la imaginación del personal de TI.