Linux Step By Steps
 

6. Integrating With Apache

There are several ways in which Tomcat can be integrated with Apache :

 

6.1 Getting the Apache-Tomcat Connectors

There are 3 connectors available at the time of this writing, and, although the documentation may say that one connector is faster than another, it really is not significant if you are using Tomcat in a low volume environment or just evaluating Tomcat for yourself. I cannot say how widely the connectors differ in terms of functionality or performance because I have not tested this out extensively.

The available connectors are :

Connector Name Apache version Remarks
Coyote / Jk2 Apache 1.3.x / 2.x [TBD]
Jk Apache 1.3.x The binaries, rpm and source versions can be downloaded here : http://jakarta.apache.org/builds/jakarta-tomcat-connectors/jk/release/v1.2.2/.
The documentation can be found here : http://jakarta.apache.org/builds/jakarta-tomcat-connectors/jk/release/v1.2.2/doc/
mod_webapp [TBD] [TBD]

A full listing of connectors, their details and documentation can be found at this URL : http://jakarta.apache.org/tomcat/tomcat-4.1-doc/config/connectors.html

 

6.2 Using mod_jk

We will be using the following components for our integration:

Tomcat 4.1.18 Binary tar file from http://apache.hjc.edu.sg/jakarta/tomcat-4/binaries/. This is Singapore's local mirror (very slow!)
Apache 1.3.27 RPM file from Red Hat, available here : http://rpmfind.net//linux/RPM/redhat/updates/7.3/i386/apache-1.3.27-2.i386.html.
mod_jk If you are using Red Hat or a Red Hat-like distribution (example : Spectra Linux), download from the Tomcat site : http://jakarta.apache.org/builds/jakarta-tomcat-connectors/jk/release/v1.2.2/rpms/mod_jk-ap13-1.2.2-1jpp.i386.rpm.
If you are using United Linux (Caldera/SCO/TurboLinux/Suse/Connectiva), download from your distribution's site.

You may notice that I am using the RPM versions for both Apache and mod_jk. Most people would use the binaries or source files and compile from there. For rpm-based Linux distributions, the added complexity and possibility of error of compiling from source is not really necessary because the Apache and mod_jk RPMs seem to work fine by themselves.

An added note about the mod_jk rpm. The file includes the binaries of mod_jk along with some "standard templates" for the configuration files that mod_jk needs in order to work properly. This can be a real boon when you need to get setup quickly, but it can also be a source of considerable frustration because it differs from the write-ups I have seen on the Internet.

Important Note !

There are significant configuration differences between RPM versions for Red Hat distributions and United Linux distributions (Caldera/SCO/Suse/TurboLinux/Connectiva) for the mod_jk connector, so take care to download the correct version for your Linux distribution.

The process of getting Tomcat to talk to Apache can be divided into the following tasks :

  1. Step 1. Install Tomcat and verify that it is working properly
  2. Step 2. Install Apache and verify that it is working properly
  3. Step 3. Shutdown both Apache and Tomcat
  4. Step 4. Install the mod_jk rpm file
  5. Step 5. Edit the configuration files, httpd.conf, mod_jk.conf, workers.properties, server.xml
  6. Step 6. Start Tomcat
  7. Step 7.Start Apache
  8. Step 8.Verify that everything works

Step 1. Install Tomcat and verify that it is working properly

Install Tomcat, then open a browser and check if you can see and execute the servlet and JSP examples bundled with it.


Step 2. Install Apache and verify that it is working properly

If you have not already installed the Apache web server, do it now. There should be no port address conflict because Apache listens on port 80 while Tomcat listens on port 8080. Verify that Apache is correctly installed by attempting to start it, then opening a browser and pointing it to http://localhost. You should see the default web server page. If you encounter any difficulties in installing or starting the Apache web server, refer to the product's website (http://httpd.apache.org/) and documentation (http://httpd.apache.org/docs/) for more information. It bears repeating that the version of Apache that I am using for this documentation is 1.3.27, and is the Red Hat rpm file.


Step 3. Shutdown both Apache and Tomcat

If both Apache and Tomcat are working fine, shutdown both of them. We are going to begin configuring them to work with each other.


Step 4. Install the mod_jk rpm file

Installing the rpm is simple. Navigate to the directory where you downloaded the file mod_jk-ap13-1.2.2-1jpp.i386.rpm and, as root, type :

# rpm -ivh mod_jk-ap13-1.2.2-1jpp.i386.rpm


Step 5. Edit the configuration files, httpd.conf, mod_jk.conf, workers.properties, server.xml

httpd.conf

After mod_jk has been successfully installed, a set of entries will be appended to the end of Apache's configuration file, httpd.conf. Look for the following lines at the end of the file :

        <IfDefine HAVE_JK>
LoadModule jk_module modules/mod_jk.so
AddModule mod_jk.c
Include /etc/httpd/conf/mod_jk.conf
</IfDefine>

If the mod_jk rpm file was successfully installed, it would have copied the file mod_jk.so into the directory /etc/httpd/modules. The LoadModule and AddModule directives are to tell the Apache web server to load the module when it starts up. One thing to note here is that, in some cases, particularly when you are using Red Hat's Apache web server rpm, the AddModule command will throw an error when the httpd daemon starts up. The error says that the module is already loaded and that it will skip this directive. You may safely comment out the AddModule command, if this is the case.

Another important thing to note is the "Include" directive, which points to an external file. A lot of documentation on Tomcat-Apache integration puts the necessary directives for integration inside httpd.conf itself. The mod_jk rpm instead places integration directives in a separate external file /etc/httpd/conf/mod_jk.conf. IMHO, this is a more sensible decision.

mod_jk.conf

This file is crucial to the integration, but before we go into it, we must first understand a few things about it. In mod_jk.conf we need to do the following :

At this point, it is a good idea to open up the mod_jk.conf that comes with the mod_jk rpm. We will examine each of the directives in the file, relating them to the tasks outlined above.

Directive Value Purpose
JkWorkersFile /etc/httpd/conf/workers.properties The location of workers.properties, a file that we will examine next.
JkLogFile /var/log/httpd/mod_jk.log The location of the log file. Depending on the error level you specify, the file will contain either very verbose information or just the critical errors.
JkLogLevel error There are 3 available options here :
  • info - logs information about mod_jk's activities
  • error - in addition to activity information, errors will also be logged
  • debug - logs anything and everything. As its name implies, this option is ideal when troubleshooting.

Following the first 3 lines of mod_jk.conf, we encounter a series of entries that relate to SSL. We will not go into this at the moment, because we want to get a "plain-vanilla" Tomcat-Apache integration going successfully first.

What follows after the SSL section are the "contexts". We have already seen earlier that "contexts" refer to web applications that are deployed inside Tomcat. We specified a <Context> element inside Tomcat's server.xml for every web application deployed, and we have to do the same here, because Apache needs to know how to hand-off requests for web applications to Tomcat.

For every web application, we must define the contexts to Apache, and we do this by supplying the following information :

We will take, as an example, the web application and servlet we developed earlier.

Web Application Name MyFirst
Location $CATALINA_HOME/webapps/MyFirst
URL we want to map to http://hostname.domain.com/MyFirst/
mod_jk Worker Name
defined inside workers.properties
ajp13

How we express this as a context in mod_jk.conf is shown below :

    #
# The following line makes apache aware of the location of the /MyFirst context
#
Alias /MyFirst "/opt/tomcat/webapps/MyFirst"
<Directory "/opt/tomcat/webapps/MyFirst">
Options Indexes FollowSymLinks
</Directory>
#
# The following line mounts all JSP files, the /servlet/ uri, and all files to tomcat
#
JkMount /MyFirst/servlet/* ajp13
JkMount /MyFirst/*.jsp ajp13
JkMount /MyFirst/* ajp13

The Location directive belongs to Apache, and is provides an access control policy based on the URL. For more information about this, click here. We may want to restrict access to the WEB-INF directory to all browsers, so we will want to append the following snippet to the bottom of the MyFirst context declaration:

    #
# The following line prohibits users from directly accessing WEB-INF
#
<Location "/start/WEB-INF/">
AllowOverride None
deny from all
</Location>

That completes our configuration for mod_jk.conf. We have 2 more files to edit before we are ready to begin testing.

workers.properties

The Tomcat-Apache worker is analogous to a connector. The workers.properties that comes with your mod_jk rpm is very verbose and defines 2 workers, named ajp12 and ajp13, and a string of other options. The options that you may need to enable and/or change are shown below :

workers.tomcat_home=/opt/tomcat Set this option to point to your Tomcat installation (i.e. $CATALINA_HOME)
workers.java_home=/opt/IBMJava2-131 Set this option to point to $JAVA_HOME
ps=/ If you're using UNIX/Linux, this is correct. For Windows systems, you will need to use the backslash ("\")
worker.list=ajp13 The default file lists both ajp12 and ajp13. This is to provide backward compatibility, but if you're reading and following this document for the first time, you probably don't need ajp12. If you delete ajp12 here, remember to comment out all ajp12 references in the file.
worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
The port number here (8009) may not be the same if you are using UnitedLinux or some earlier Red Hat rpms. Be advised that Tomcat defaults to this port number, and if you have difficulties getting your integration to work, the first place to look should be here. Ensure that the port number here and the one defined in your server.xml agree.
worker.ajp13.lbfactor=50 This is the load balancing factor. Default is 1, which means that less work should be done by the worker. If you have a really powerful machine, you can up this to 50 or more.
worker.ajp13.cachesize=10 Set this to the typical number of concurrent connections you are expecting.
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=ajp13
This is a list of workers that the Load Balancer needs to manage. For more information about load balancing, please see this.
worker.inprocess.type=jni This option tells the jni worker to open a JVM inside the web server process and execute Tomcat within it (in-process).
worker.inprocess.class_path=
$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar
This option specifies the classpath to be used by the in-process JVM
worker.inprocess.cmd_line=start This specifies the command line properties that are handed over to Tomcats' startup code
worker.inprocess.jvm_lib=
$(workers.java_home)$(ps)jre$(ps)bin$(ps)classic$(ps)libjvm.so
Uncomment the option that is most relevant to the JVM you are using
worker.inprocess.stdout=
$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stdout
worker.inprocess.stderr=
$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stderr
stdout is the full path to where the JVM write its System.out, while stderr is the full path to where the JVM write its System.err
worker.inprocess.sysprops=tomcat.home=
$(workers.tomcat_home)
The System properties of the JVM

server.xml

This is the last file you will need to edit, before testing the integration, so hang in there !

You will first need to comment out JMX Beans support. This will throw an error when Tomcat and Apache are started because Tomcat assumes that you are using this functionality by default. Locate the following lines and comment them out.

  <!-- Comment these entries out to disable JMX MBeans support -->
<!-- You may also configure custom components (e.g. Valves/Realms) by
including your own mbean-descriptor file(s), and setting the
"descriptors" attribute to point to a ';' seperated list of paths
(in the ClassLoader sense) of files to add to the default list.
e.g. descriptors="/com/myfirm/mypackage/mbean-descriptor.xml"
-->
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"
debug="0"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
debug="0"/>

Not sure how to comment them out ? Well, the commented out section above should look like the section below.

  <!-- Comment these entries out to disable JMX MBeans support -->
<!-- You may also configure custom components (e.g. Valves/Realms) by
including your own mbean-descriptor file(s), and setting the
"descriptors" attribute to point to a ';' seperated list of paths
(in the ClassLoader sense) of files to add to the default list.
e.g. descriptors="/com/myfirm/mypackage/mbean-descriptor.xml"
-->
<!--
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"
debug="0"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
debug="0"/>
-->

Next we need to comment out the default non-SSL Coyote connector. Bear in mind that, unlike earlier versions of Tomcat, disabling this connector means that Tomcat is no longer directly accessible from the default "8080" port, but instead will receive all requests via Apache.

    <!-- Define a non-SSL Coyote HTTP/1.1 Connector on port 8080 -->
<!--
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8080" minProcessors="5" maxProcessors="75"
enableLookups="true" redirectPort="8443"
acceptCount="100" debug="0" connectionTimeout="20000"
useURIValidationHack="false" disableUploadTimeout="true" />
-->

Another section to comment out is the default Coyote/JK2 connector, because we're not using this to connect Apache with Tomcat.

    <!-- Define a Coyote/JK2 AJP 1.3 Connector on port 8009 -->
<!--
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8009" minProcessors="5" maxProcessors="75"
enableLookups="true" redirectPort="8443"
acceptCount="10" debug="0" connectionTimeout="0"
useURIValidationHack="false"
protocolHandlerClassName="org.apache.jk.server.JkCoyoteHandler"/>
-->

Now, we need to uncomment the JK connector to enable it.

    <!-- Define an AJP 1.3 Connector on port 8009 -->

<Connector className="org.apache.ajp.tomcat4.Ajp13Connector"
port="8009" minProcessors="5" maxProcessors="75"
acceptCount="10" debug="0"/>

And that's it! Save the file, shutdown Tomcat and Apache, if both are currently running and we're ready to test.

Important Note ! If you wish to use the admin and manager web applications in Tomcat, you WILL need MBeans support. This means that you should leave the MBeans listeners uncommented, and use the Coyote/JK2 AJP1.3 Connector on port 8009 section, instead of the AJP 1.3 Connector section.

Step 6. Start Tomcat

The startup sequence, after you have configured Tomcat to communicate with Apache is always to start Tomcat first. If you're running Tomcat on a system that has a slow processor or not enough RAM, you will find that Tomcat starts rather slowly. To check on the progress of the startup, do a 'tail -f $CATALINA_HOME/logs/catalina.out' and see the messages.

Step 7. Start Apache

Once Tomcat has started up, you can start Apache.

Step 8. Verify that everything works

Open a browser and key in the URL. For our web application 'MyFirst', the URL to key in for the HelloWorld servlet would be "http://localhost/MyFirst/HelloWorld". If you get an error, check to see if you followed the instructions closely. Another thing to check are the error logs.

One common source of error is the JK port. If you get an error that says that Apache is unable to communicate with Tomcat, check the port address in your workers.properties and compare it with the one defined in server.xml. They should be the same. If not, just change the values so both agree.

If everything works, congratulations ! You have successfully integrated Apache and Tomcat !