Virtual hosts com Tomcat
Este post foi originalmente publicado no meu blog – /dev/Kico – porém, como estou escrevendo bastante aqui sobre servidores, e recentemente falamos sobre o conceito de hosts virtuais aplicados ao Apache, creio que caiba bem aqui na revista também com algumas adaptações.
Imagine a seguinte situação: você tem um único servidor e duas aplicações distintas que serão hospedadas na mesma máquina. Cada uma destas aplicações tem, por sua vez, seu próprio domínio (www.aplicacaoquente.com.br (aplicação A) e www.aplicacaofervente.com.br (aplicação B), por exemplo). Como você resolve esta questão usando apenas o Tomcat?
Se você tiver o servidor Apache instalado, é possível usá-lo como front-end do seu servidor e, configurando o recurso do proxy reverso, simplesmente fazer o direcionamento das requisições vindas dos dois domínios acima para as aplicações A ou B. Mas e quando você tem apenas o Tomcat? Razoavelmente simples: você usa o recurso dos hosts virtuais (virtual hosts daqui pra frente).
(A documentação oficial do Tomcat sobre este tema é muito ruim, e isto me motivou a escrever este post.)
O que é um host virtual?
Um host virtual representa o direcionamento que o Tomcat fará quando receber solicitações para um dado domínio. No exemplo deste post, temos os dois domínios, um para cada uma das aplicações. Vamos ver aqui agora como realizar esta configuração na versão 8.0 e 8.5 do Tomcat (se aplica também à versão 9.0 do servidor).
Como configurar os virtual hosts
Antes de iniciar, uma simples convenção. CATALINA_HOME representa o diretório no qual o Apache Tomcat encontra-se instalado em seu servidor.
O primeiro passo consiste em editar o arquivo CATALINA_HOME/conf/server.xml. Busque pela tag <Engine> cujo atributo name seja igual a “Catalina”, tal como no exemplo a seguir:
<Engine name="Catalina" defaultHost="localhost"> <!--For clustering, please take a look at documentation at:
É no interior desta tag que iremos inserir as configurações de nossos virtual hosts. A configuração é bastante simples. Em nosso exemplo, basta incluir duas tags <Host>, tal como no exemplo a seguir:
<Host name="aplicacaofervente.com.br" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Alias>www.aplicacaofervente.com.br</Alias> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="aplicacaofervente_access_log" suffix=".txt" pattern="%h %l %u %t %r %s %b" /> </Host> <Host name="aplicacaoquente.com.br" appBase="webapps2" unpackWARs="true" autoDeploy="true"> <Alias>www.aplicacaoquente.com.br</Alias> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="aplicacaoquente_access_log" suffix=".txt" pattern="%h %l %u %t %r %s %b" /> </Host>
Muita atenção a alguns atributos muito importantes presentes na tag <Host>:
- appBase – define o diretório “webapps” daquele host. No caso de virtual hosts, é uma boa ideia você ter um diretório “webapps” por host. Em nosso exemplo, criei dois diretórios: CATALINA_HOME/webapps e CATALINA_HOME/webapps2
- name – identifica o domínio para o qual serão direcionadas as requisições. Observe que defini o domínio sem o “www” na frente. Isto por que no interior da tag <Host> podemos incluir aliases, observe a tag <Alias>: ela inclui o prefixo no nome do domńio, o “www”.
A tag <Valve> neste caso é usada para configurar uma válvula do Tomcat (um recurso poderosíssimo e muito pouco conhecido pelos desenvolvedores) responsável por registrar as requisições que chegam ao servidor em um arquivo de log. Observe que criei um arquivo de log por domínio.
Muita atenção em relação à pasta appBase
É possível ter dois virtual hosts apontando para a mesma pasta appBase. Entretanto, em diversas situações você observará que as aplicações, durante sua inicialização, entram em “loop de boot”, ou seja, são iniciadas e reiniciadas infinitas vezes.
Não sei ao certo o que causa este problema, mas sei como solucioná-lo: uma pasta appBase por host. Simples assim.
Alguns links úteis
É interessante que você conheça os atributos que podem ser inseridos nas tags <Engine> e <Host>. Sendo assim, recomendo que leia sobre a primeira tag aqui e sobre a segunda aqui.
Definindo o host padrão
Com isto nosso servidor está praticamente pronto. O mesmo endereço IP irá atender aos dois domínios. Mas e se alguém tentar acessar o servidor diretamente pelo seu IP? Neste caso definimos qual o host padrão na tag <Engine>, tal como exposto no exemplo a seguir:
<Engine name="Catalina" defaultHost="localhost">
Neste exemplo criei uma tag <Host> cujo nome é “localhost” (é inclusive o host padrão da configuração limpa do Tomcat).
Sobre o contexto das aplicações em um domínio
Se você já usou o Tomcat sabe que é possível ter mais de uma aplicação instalada na pasta CATALINA_HOME/webapps. Voltando ao nosso exemplo, imagine que para o domínio aplicacaofervente.com.br tivéssemos os seguintes arquivos WAR na sua pasta webapps:
- ROOT.war
- administrativo.war
A aplicação padrão do domínio seria o ROOT.war. Já se você quiser aplicar o administrativo, teria de usar o endereço http://www.aplicacaofervente.com.br/administrativo
Melhorias no consumo de memória
Talvez as aplicações que você hospeda em seus virtual hosts tenham bibliotecas em comum. Apenas se você tiver certeza absoluta de que compartilham exatamente as mesmas versões destas bibliotecas, considere a configuração de uma pasta compartilhada de libs. Recomendo a leitura desta página na documentação oficial do Tomcat sobre class loading.
Concluindo
Reinicie o seu Tomcat e faça testes enviando requisições para os dois domínios que apontam para o mesmo IP e veja o resultado. Na sequência, acesse o servidor diretamente por seu IP e verá ser retornada a aplicação padrão definida na tag <Engine>.
O Tomcat é cheio de recursos muito interessantes que os desenvolvedores desconhecem. Em um futuro próximo talvez escreva mais dicas sobre estes assuntos (dica: leia sobre as válvulas).
PS: Uma ideia para o futuro (próximo)
quem sabe, assim como estou escrevendo um guia do Apache, no futuro este também não se torne o primeiro post de um guia do Tomcat, hein?
É outro servidor muito usado mas cujas entranhas são pouquíssimo conhecidas por desenvolvedores Java (ou que usem a JVM)!
Desenvolvedor e co-fundador da itexto, do /dev/All, Groovy e Grails Brasil, Spring Brasil e JavaScript Brasil.
Desenvolvendo software desde o século passado e escrevendo a respeito no /dev/Kico