En esta entrada voy a hablar sobre el despliegue de aplicaciones web en Apache Tomcat. Partimos de la situación cuando tenemos que desplegar una aplicación web en Tomcat que está detrás de un front-end que puede ser Apache, nginx o cualquier otro. Se supone que en el caso de Apache se usa mod_proxy.
Objetivos:
- Queremos usar la aplicación Deployer que viene junto a Tomcat y que nos permite desplegar/replegar/parar/arrancar/reiniciar aplicaciones directamente desde un navegador web.
- La gestión de hosts virtuales lo dejamos para el front-end en vez de poner múltiples Alias en server.xml.
Existen muchos inconvenientes si dejamos a Tomcat tratar todas las peticiones HTTP. En primer lugar cada petición HTTP va a ocupar bastante más memoria y gastar más tiempo CPU si se trata con Tomcat en vez de con un servidor apropiado, como puede ser Apache o nginx. En segundo lugar, si la petición se procesa mediante Tomcat en primer lugar no se podrá hacer uso de todos los módulos disponibles para Apache. Por último, cada aplicación está hecha para su cosa y para atender peticiónes HTTP están los Apache y nginx y para hacer uso de servlets está el Tomcat.
Primero vamos a configurar el servidor de aplicaciones. Para la explicación de todas las directrices para la configuración de Tomcat se puede echar un ojo a la documentación oficial. Tenemos que conseguir que haya solamente un Engine y un sólo Host que va a ser el que trate las peticiones por defecto. Dentro del Host definiremos un Context que contendrá la aplicación Manager.
La configuración que tengo yo en producción es la siguiente:
<Service name="Catalina">
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol" URIEncoding="UTF-8" maxThreads="100" port="8080" emptySessionPath="true" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
<Context path="/manager" debug="0" privileged="true" docBase="/path/webapps/manager">
</Context>
</Host>
</Engine>
</Service>
Ahora tenemos que conseguir que el front-end redireccione las peticiones del navegador a http://localhost:8080/manager. Yo lo hago con un dominio de tercer nivel y mod_rewrite. Con mod_rewrite vamos a redireccionar todos los dominios, pero de momento resolvemos el tema de Manager.
En primer lugar he creado un nuevo dominio de tercer nivel apuntando a la máquina. Pongamos por ejemplo http://manager.dominio.com. Luego lo he configurado en Apache para que mediante mod_rewrite se transforme en http://localhost:8080/manager. Las directrices son las siguientes:
<VirtualHost *:80>
ServerName manager.dominio.com
RewriteRule (.*) /manager/$1 [NS,PT,L]
ProxyPreserveHost On
ProxyPass /manager http://localhost:8080/manager
ProxyPassReverse /manager http://localhost:8080/manager
</VirtualHost>
Con esto lo que conseguimos es que si apuntamos el navegador web a http://manager.dominio.com Apache va a pasar la petición a http://localhost:8080/manager, el Tomcat la ejecutará y devolverá la respuesta a Apache y este a su vez la devolverá al navegador. Realmente es un mal ejemplo, porque lo que tenemos que conseguir es que Tomcat procese únicamente los servlets, sin embargo aquí le decimos (con (.*)) que procese todo. Es decir, que si el navegador pide una imagen, esta también será devuelta por Tomcat. Es un mal ejemplo, pero por algo tenemos que empezar.
Una vez que tengamos acceso a la aplicación manager ya podemos desplegar otras. Tan sólo tenemos que generar un fichero war y hacer uso del cuadro WAR file to deploy, el resto lo hará el Tomcat, descomprimirá el fichero war dentro del directorio webapp y hará disponible la aplicación en el contexto http://localhost:8080/NombreFicheroWAR.
Ahora tenemos que configurar Apache para que trate las peticiones. Defineremos lo siguiente:
- Que todas las peticiones de servlets las procese el Tomcat.
- Que todas las demás peticiones las procese el front-end.
En cuanto al primer punto podemos hacerlo de dos formas. O bien definir un RewriteRule para cada servlet, o bien definir un patrón para los servlets y seguir este patrón a la hora de poner los url-pattern en el fichero web.xml. En cuanto al segundo es suficiente con poner como DocumentRoot la dirección donde va a descomprimir Tomcat el fichero. Hay una cosa superimportante que tenemos que recordar siempre, y es que tenemos que prohibir el acceso a todo el mundo a los directorios WEB-INF y META-INF. En Apache es sencillo:
<Location "/WEB-INF/*">
AllowOverride None
Deny from all
</Location>
<Location "/META-INF/*">
AllowOverride None
Deny from all
</Location>
Si no hacemos esto pondremos en peligro la seguridad de la aplicación entera ya que cualquiera podría descargar las clases compiladas, descompilarlas, etc.
Recursos relacionados: