jump to navigation

Apache mod_jk and tomcat with multiple virtual hosts November 22, 2008

Posted by maxmil in : Apache,tomcat , trackback

I recently had to configure a couple of different tomcat web applications as virtual hosts, each with its own domain. Although in my case tomcat is serving all the content of these applications i decided to use mod_jk to clean up the URL's and profit from apache's load balancing.

I found plenty of articles on the web that explained how to install and configure mod_jk with tomcat. However they all mapped an apache virtual host to a root tomcat context. Since i had two different tomcat context this seemed to mean that i would have to install two tomcat instances which was not a ideal solution.

The answer to my dilema was to define two separate hosts in tomcat, each one with its own mod_jk worker and one weapp as its root context. This idea came from Grig Gheorghiu. Thanks Grig!

I thought it would be worth describing the steps i took in a post so that others might benefit.

So here goes… My environment is:

Debian Lenny, Apache2.2, Tomcat 6.0.16.

http://test.domain1.org must map to webapp-domain1.war
http://test.domain2.org must map to webapp-domain2.war


Step 1: Installation and configuration of apache mod_jk

I run debian so this was as easy as

apt-get install libapache-mod-jk
On other systems this probably involves downloading the mod_jk.so for your apache and loading the module in your htttpd.conf.

You must then proceed to configure a file called workers.properties mod_jk. You need to create a separate worker for each of your domains. Here's my workers.properties file that i saved in /etc/apache. You can find out more about the options available in this file here

workers.tomcat_home=/usr/local/tomcat/apache-tomcat-6.0.16
workers.java_home=/usr/lib/jvm/java-6-sun
ps=/
worker.list=worker1,worker2
worker.worker1.type=ajp13
worker.worker1.host=test.domain1.org
worker.worker1.port=8009
worker.worker2.type=ajp13
worker.worker2.host=test.domain2.org
worker.worker2.port=8009


Step 2: Creation of virtual hosts on apache

Next you should create a couple of virtual hosts on apache. I use name based virtual hosts. More info can be found here.

In my case these didn’t need to have document roots since i let the workers map all requests to tomcat. Note that if you do configure your apache to serve content from within your expanded web application you should take care to make sure that access to WEB-INF is controlled.

Here are my minimal virtual hosts. The JKMount /* lines pass all requests to tomcat. More info on JKMount options can be found here.

<VirtualHost *:80>
   ServerName test.domain1.org
   JkMount /* worker1
</VirtualHost>

<VirtualHost *:80>
   ServerName test.domain2.org
   JkMount /* worker2
</VirtualHost>

Now reload apache and check that you have no errors.


Step 3: Configuration of mod_jk listener in tomcat

In order for tomcat to listen for the workers you defined you need to add a line like this to the engine element on your tomcat server.xml file.

<Listener className="org.apache.jk.config.ApacheConfig"
      modJk="/usr/lib/apache2/modules/mod_jk.so"
      workersConfig="/etc/apache2/workers.properties"/>

Don’t forget to modify the paths for your system.


Step 4: Configuration of tomcat hosts

For each domain you now need to create a new tomcat host. The name of each host should correspond with the host you defined in each of your workers, test.domain1.org and test.domain2.org in my case.

You also have to define a appBase for each host which is where its webapps will reside by default.

I copied the host element from the default host. Here are my host elements. More info on host elements can be found here.

<Host name="test.domain1.org"
   appBase="/var/tomcat/domain1"
   unpackWARs="true"
   autoDeploy="true"
   xmlValidation="false"
   xmlNamespaceAware="false">

<Host name="test.domain2.org"
   appBase="/var/tomcat/domain2"
   unpackWARs="true"
   autoDeploy="true"
   xmlValidation="false"
   xmlNamespaceAware="false">

I didn’t find any documentation on this but i needed to copy the host-manager context from the default hosts webapps folder to each of my new hosts.

Then you must then copy your war files to each of your hosts and rename them to ROOT.war.

If you don’t rename them but create a Context element in your host with docBase=”yourwarfile.war” and path=””. The first time the server starts it will expand the contents of this file to ROOT. However i found that after updating the war file the contents were expanded to a new directory with the same name as the war file rather than the ROOT directory. Hence the ROOT context does not get updated and you don’t see your changes. This may or may not be considered a bug, but is at the very least confusing behavior.


Step 5: Test and enjoy

Fireup tomcat, have a look at the log to make sure that both your hosts have been started without any errors and then open a browser and naviagate to:

http://test.domain1.org and http://test.domain2.org

If everything is set up correctly you’ll be looking at the home page of each of your two web applications.

Comments»

1. Sanjay - January 13, 2009

Hi MaxMil, very useful info. Something I have been looking for since weeks. I followed all instructions discussed here but successfully implement. Request you to elaborate on
Step 4: Configuration of tomcat hosts
Please tell me what exactly to be done especially when we dont have .war application but bunch of jsp code.

2. Sanjay - January 13, 2009

oops…typo….
COULDNT SUCCESSFULLY IMPLEMENT

3. maxmil - January 13, 2009

Your jsp’s must still be organized in an expanded war file directory structure. The folder that contains the root of your webapp is the folder that contains WEB-INF and your jsps.

This is the folder that you should copy to your host and rename as ROOT.

4. Kalam - February 12, 2009

Thanks a lot dude!!!!! :)

I had a few hiccups, but eventually managed to do it. Strangely, mod_jk was working fine without any workers.properties (I was using it for a single website which mounted /*). But I had to add it for the multiple hosts.

This is a really useful & concise tutorial.

5. Ivan - July 15, 2009

Very nice read :-) Thanks for the effort.
You have a typo. (http://test.domain1.org must map to webapp-domain2.war)

6. Chris Hall - August 10, 2009

Thank you very much for this it’s exactly what I have been looking for and works perfectly.

7. Alparslan - September 30, 2009

Hi,
I’ve configure apache vhost like this:

JkMount /* worker2

everything okey my application work like this:

http://servername/app1

but Now I want to map the app1 to root of the web site without change the codes.

for example the app1 should work like this

http://servername/

is there any way to map application to root on the website?

thanks best regards?

note: this configuration doesn’t work

JkMount /app1/* worker2

8. Alparslan - September 30, 2009

this is the redirect rule for my app1 but I want don’t see app1 directory root of the website…..

RedirectMatch ^/$ /app1

9. maxmil - September 30, 2009

If i understand correctly you need to specify the serverName in your virtual host.

ie if your domain is mydomain.org

ServerName mydomain.org

10. Jitendra - December 2, 2009

Hi,

Can you please elaborate “I didn’t find any documentation on this but i needed to copy the host-manager context from the default hosts webapps folder to each of my new hosts.”

How do we do it ?

If I have Host Manager Tomcat App running at Root, would i need to delete this ?

Thanks
Jeet

11. maxmil - December 3, 2009

You don’t need to delete it. Just copy it to each of your new hosts.

You will need to stop the server first.

12. Narayan - February 5, 2010

Thanks for the clear info.I deployed a .war on IBM Websphere with Apache and it works great on a Suse Linux 11.2 rack server. Thanks again.

13. Kyle Turner - March 16, 2011

One thing it’s probably worth noting (at least, took me an hour or two to realize), apache’s modjk may fail to connect to tomcat if the hostname (in workers.properties and server.xml) isn’t listed in /etc/hosts as a loopback. I think this is because the connection may otherwise be treated as an external connection and be blocked by an aggressive firewall.

14. Shanif - May 24, 2012

This blog helped me solve an issue in one hour that was preventing me from moving forward for more than a day.

Thank you!