Uma instância do Tomcat atendendo dois domínios? Configurando Virtual Hosts

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.

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:


&lt;Engine name="Catalina" defaultHost="localhost"&gt;

&lt;!--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:


&lt;Host name="aplicacaofervente.com.br" appBase="webapps" unpackWARs="true" autoDeploy="true"&gt;
&lt;Alias&gt;www.aplicacaofervente.com.br&lt;/Alias&gt;

&lt;Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" &nbsp; prefix="aplicacaofervente_access_log" suffix=".txt"
pattern="%h %l %u %t %r %s %b" /&gt;
&lt;/Host&gt;

&lt;Host name="aplicacaoquente.com.br" appBase="webapps2" unpackWARs="true" autoDeploy="true"&gt;
&lt;Alias&gt;www.aplicacaoquente.com.br&lt;/Alias&gt;

&lt;Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="aplicacaoquente_access_log" suffix=".txt"
pattern="%h %l %u %t %r %s %b" /&gt;
&lt;/Host&gt;

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:


&lt;Engine name="Catalina" defaultHost="localhost"&gt;

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).

21