Connecting Apache to Tomcat


Of course, with all howtos, I assume no responsibility for anything bad that happens if you follow the advice contained in these documents. I'm merely trying to be helpful, by conveying what worked for me. By implementing my advice, you are implicitly accepting this disclaimer. Comments are appreciated, though.


Since Apache is the world's most popular webserver, and Tomcat is the
world's least expensive java application server, I would assume that a lot of
people would be trying to use them together, especially since the Jakarta web
site tells you that Tomcat's built-in web server is not really meant for deployment.
Unfortunately, the process of actually getting these two products to work
together has given me no end of grief, and the pages the Apache/Jakarta folks
have put together explaining this process never have worked for me.  Perhaps
it's because they change the entire connector scheme for every new version of
their products.   Argh.

Anyway, here's a description of how I got Apache and Tomcat to work together.
I'm sure this description won't be any more universal than the other pages you've
found on this, but since none of those helped me make it work, I at least hope
this page fills a void.

My Configuration


What I actually got to work:

First Successful Try:
Apache HTTP server 1.3.26
mod_ssl  2.8.10
Tomcat 4.0.4 App Server
SuSE Linux 8.1 kernel 2.4.19
mod_jk 1.2.5 connector

Second Succesful Try:
Apache HTTP server 1.3.26
mod_ssl 2.8.10
Tomcat 5.0.16 App Server
SuSE Linux 8.1 kernel 2.4.21
mod_jk2 connector (bundled with Tomcat 5.0.16)
Apache Portable Runtime (apr) 0.9.4

I read some places that the jk2 connector wasn't meant for Apace 1.3.x, but I got
it to work.  I looked into migrating to Apache 2, but it didn't look doable.  The
majority of users (and mail-list/howto/help) posts I've found suggest that unless you
love pain, don't bother going to Apache 2 yet (Dec03).  Also, how https support is handled
in Apache 2 is not clear to me.  Mod_ssl still seems to be geared toward 1.3.x.  Sadly,
I think you're in for pain regardless of which way you go if you're set on using Apache
and Tomcat, but hopefully I can help.

The Steps


1) First, get the source and/or rpms.  This isn't an Apache or Tomcat install howto, so
I'll assume you have both of those working fine by themselves, and your problem is just
connecting them transparently, so that Apache is dispatching all JSP requests to Tomcat
withouth the client being aware of the dual-headed server.

2) I would recommend getting source for the Tomcat version that matches your installation,
even if you installed Tomcat with binaries.  You probably could just get the connector
source, but that's not what I did for my second configuration, so that's not how I'm
writing this howto.  Again, in my case, that was Tomcat 4.0.4 first, and then 5.0.16.

First Configuration (Tomcat 4.0.4 / mod_jk)


3) For this, I did use the separate source distribution for Tomcat JK connectors:
jakarta-tomcat-connectors-jk-1.2.5-src

cd /usr/src/jakarta-tomcat-connectors-jk-1.2.5-src/
cd jk/native/

4) Use the configure scripts to configure your build:

./buildconf.sh
./configure -with-apxs=/usr/sbin/apxs

It should be noted that the docs recommend adding this to your configure flags:
--enable-EAPI
 This parameter is needed when using Apache-1.3 and mod_ssl, otherwise you
 will get the error message: "this module might crash under EAPI!" when
 loading libjk.so in httpd.

I didn't do it, and don't quite remember why not, since I am using Apache 1.3 and
mod_ssl.  But, I never saw any problems ... just thought I'd let you know.

5)  Then, build the Apache connector module:
make
cp apache-1.3/mod_jk.so /usr/lib/apache/mod_jk.so
cd /usr/lib/apache

Make sure /usr/lib/apache is actually where you have the mod*.so files for your httpd
installation.

6) Next, you have to alter the Apache httpd.conf file for loading the new module.  I have
to assume the process of module loading into Apache isn't a new subject.  Otherwise,
consult the Apache httpd docs on Modules.

Here are excerpts from my httpd.conf file:
#LoadModule jk_module          /usr/lib/apache/mod_jk.so
#AddModule mod_jk.c

Then, in my VirtualHost section for the secure website, I include a file where I keep all
the JSP specific settings I want.  You could of course keep them right in httpd.conf,  but it
makes more sense to me to keep these settings in the $CATALINA_HOME/conf folder
where the other tomcat configuration files are.

Include /opt/jakarta/tomcat/conf/tomcat_jk_ssl.conf

And finally, in the main section (http, not https) of httpd.conf, I have this include directive:

Include /opt/jakarta/tomcat/conf/tomcat_jk.conf

Obviously, my Tomcat installation ($CATALINA_HOME) is /opt/jakarta/tomcat

7) Now, setup the tomcat_jk.conf files.  Here you give directives to Apache on which
tomcat webapp directories get which permissions, and what Tomcat applications (contexts)
you wish to "map" or "alias" to the normal Apache HTTP URL space.

Here is a look at my http file.  The tomcat_jk_ssl.conf file is exactly the same, just pointing
to those webapps which you prefer to only publish on your secure (https://my.domain.name.com)
site.  For obvious reasons, I'm not showing you exactly what my file looks like.
# simple configuration for apache (for AJP connector, modul mod_jk.so)

JkWorkersFile /opt/jakarta/tomcat/conf/workers.properties
JkLogFile /opt/jakarta/tomcat/logs/mod_jk.log # Log level to be used by mod_jk JkLogLevel error # The following line makes apache aware of the location of # the /examples context #JkAutoAlias /var/www/htdocs/jsp #JkAutoAlias /opt/jakarta/tomcat/webapps Alias /print "/opt/jakarta/tomcat/webapps/print" Alias /examples "/opt/jakarta/tomcat/webapps/examples" <Directory "/opt/jakarta/tomcat/webapps">     Options Indexes FollowSymLinks -Includes MultiViews     Order Deny,Allow     Allow from all </Directory> #JkOptions indicate to send SSL KEY SIZE, #JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories # The following line mounts all JSP files and the /servlet/ uri to tomcat JkMount /examples/servlet/* ajp13 JkMount /examples/*.jsp ajp13 JkMount /print/*.jsp ajp13 # The following line prohibits users from directly accessing WEB-INF <Location "/*/WEB-INF/">     AllowOverride None     deny from all </Location>
I won't explain all these settings.  You can use the Apache/Tomcat docs for
descriptions.  Basically, the workers.properties file is where you specify the
connection parameters for how Apache's httpd is to communication with the
Tomcat server.  The alias directives are needed so that the httpd doesn't tell
you "File Not Found" when a client asks it for a file not under its not document
base (e.g. /var/www/htdocs).  There is no need to keep your Tomcat webapps
under the same file root as the Apache normal HTML docs.  For those
context names (e.g. "/print" or "/examples" in my case) that are aliased, httpd will
simple forward the request to Tomcat.  Finally, the JkMount directive mount
specific filenames (or wildcard filenames) to Apache.  So both the context (ala a
folder name) and the JSP filename are specified to Apache via this file.

You can also use this file to specify restrictions on directory access just like you
normally would for any folders served by Apache.  For secure webapp folders,
you might add lines like these to the section:

    AuthType Basic
    AuthName "Apache/Tomcat secure realm"
    AuthUserFile /etc/httpd/passwd/passwords
 
8) Then, you have to activate the Tomcat side of the JK connector in the tomcat
server.xml file:

<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector className="org.apache.ajp.tomcat4.Ajp13Connector" 
   port="8009" minProcessors="25" maxProcessors="75"
   enableLookups="false" disableLookups="true" tcpNoDelay="true" 
   acceptCount="10" debug="0" connectionTimeout="-1"/>

This will make Tomcat listen on port 8009 for forwarded request from Apache httpd.

9) Finally, you have to make the settings match in the workers.properties file I
mentioned earlier.  I won't show you the whole file.  Your Tomcat distro should give
you a default version of the file.  These are the lines I played with:

worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13

If Tomcat is on a different host than Apache, substitute that hostname for 'localhost' above.
Mine were on the same server, so localhost did it for me.  If the two are on different
servers separated by a firewall, you may have more problems.   Do some searching on
the socket_keepalive property.  I think that may help you:

# worker ajp13 ask operating system to send KEEP-ALIVE signal on the connection
worker.ajp13.socket_keepalive=1

10) Then, you should be ready to restart everything, and give it a shot!

Second Configuration (Tomcat 5.0.16 / mod_jk2)


3)  This installation was a little different (worse), and I wound up making some mods to the
very poorly documented process that the Jakarta folks give you.  I made it look a little
more like my previous 4.0.4 mod_jk configuration.  Hey, it worked.

4) First, get the source (I got the source for all of Tomcat 5.0.16 in one bundle, including the
jk2 connector.  Also, jk2 requires the Apache Portable Runtime, which comes with the Apache
2 server, but not with 1.3.  So, you'll need to go find a source distro of the Runtime, called
apr.  I used apr-0.9.4 and apr-util-0.9.4.

5) Untar the APR into /usr/src, or wherever you like to build stuff.  Then build it.  This didn't
really work for me, but I'll show you what I did anyway.

cd /usr/src/apr-0.9.4
./buildconf.sh
./configure
make

Then, do the APR util package.

cd /usr/src/apr-util-0.9.4
./buildconf.sh
./configure --with-apr=../apr-0.9.4
make

Then, you are left with some static libraries, named lib*.a* in the .libs subdirectory.  I didn't want
to rebuild Apache from scratch with those static libs inside, so I really wanted shared object (so)
files to load dynamically.  However, the APR documentation is awful, and I couldn't quickly
figure out how to build shared libs.  My makefile only build .a files.  So, what I tried was going into
my apache 2 installation directory (I have it installed just for test purposes, not deployment) and
I found some APR shared libs in there.  They were a slightly older version, but I was hoping that
wouldn't matter.  The mod_jk2 code is what depends on APR, not vice versa, so I was hopeful
that the versioning wouldn't be tighly tied together.  It wasn't.  I just copied the APR libraries into
the Apache 1.3 modules directory:

/usr/lib/apache/apr.exp      /usr/lib/apache/libapr-0.la    /usr/lib/apache/libapr-0.so.0.9.3 
/usr/lib/apache/libaprutil-0.so
/usr/lib/apache/aprutil.exp  /usr/lib/apache/libapr-0.so    /usr/lib/apache/libaprutil-0.a    
/usr/lib/apache/libaprutil-0.so.0
/usr/lib/apache/libapr-0.a   /usr/lib/apache/libapr-0.so.0  /usr/lib/apache/libaprutil-0.la   
/usr/lib/apache/libaprutil-0.so.0.9.3

6)  Then, you need to build the mod_jk2 connector, which depends on the Apache version, and
APR version you're integrating with.  So, you'll need to configure the connector source as follows:

cd /usr/src/jakarta-tomcat-5.0.16-src/src/jakarta-tomcat-connectors/jk/native2
./buildconf.sh
./configure -with-apxs=/usr/sbin/apxs --enable-EAPI --with-apr=/usr/src/apr-0.9.4 --with-apr-util=/usr/src/apr-util-0.9.4

Make sure that the version of apxs you point to is exactly the version that goes with the version of
Apache your going to be using.  I actually slightly mismatched this once (1.3.26 vs. 1.3.29) and it
caused major breakage.  

Also, you may notice that I point to the APR 0.9.4 source tree even though I installed the shared libraries
that I got from the Apache 2 install that had a 0.9.3 version.  That could potentially be a problem, but
it wasn't for me, so I didn't worry about it.  Hopefully, the APR author has got enough stability in his
interfaces that this isn't a big deal.  But, if you want to, it would clearly be better to get the source that
matches (if not 'produces') your APR share libs.  So don't do like I did!!

7) After this, you should be set to do your build.  Unfortunately, it doesn't look like this source gets
a lot of testing before it's released, so I had to modify a couple of files to actually get the build to
work.  A couple script file permissions needed changing (chmod +x), and there were some compile errors,
too.   A couple of files had C preprocessor directive in them like this:

#error "This file is deprecated"

Which causes the build to fail.  I had no idea what to do to fix that, so I just removed the #error lines
are recompiled.  It worked.  Deprecation usually isn't a show-stopper if you ignore it, so I just
plodded on.

Next, I got some errors in the Makefiles that the buildconf and configure scripts produce.  First of all,
there were malformatted library include lines that caused the following error:

/usr/local/java/jre/lib/: file not recognized: Is a directory
collect2: ld returned 1 exit status

I had to change
jakarta-tomcat-5.0.16-src/src/jakarta-tomcat-connectors/jk/native2/server/apache13/Makefile:
JAVA_LIB=-L ${JAVA_HOME}/jre/lib/${ARCH} -L ${JAVA_HOME}/lib/${ARCH}/native_threads
to
JAVA_LIB=-L${JAVA_HOME}/jre/lib/${ARCH} -L${JAVA_HOME}/lib/${ARCH}/native_threads

Basically, in case you can't tell, I just removed a couple of spaces after the -L instances.

Then, the had to change Makefile.apxs in the same apache13 folder:
mod_jk2.so:
        $(APXS) -c -o $@ -Wc,"${JK_INCL} ${APR_CFLAGS} ${APR_LDFLAGS}" "${JAVA_INCL}" ${C_FILES} ${COMMON_C_FILES}

I don't know why there are quotes in this line.  They caused errors for my build, so I removed
them (all the " chars).  At last, you should do

make

and verify the existence of a jakarta-tomcat-connectors/jk/build/jk2/apache13/mod_jk2.so file.
Install this libary by copying it to your apache lib directory (e.g. /usr/lib/apache), and making sure the
permissions are ok.

8)  From here, the process gets similar to the first installation branch I described.  In your httpd.conf
file, add the LoadModule and AddModule lines as before, except that you replace mod_jk with
mod_jk2.

9) However, since you have a new jk2 module that depends on the APR, you also need to load
those libraries.  Also, unless you build thread support into your Apache (which I didn't),
then, you need  to load the pthread shared library (that should come with your Linux distro).

So, my httpd.conf file also has these lines, near the very start:
LoadFile /usr/lib/libpthread.so
LoadFile /usr/lib/apache/libapr-0.so

If you don't have these, upon starting the httpd you will get loader errors that pthread, or apr
symbols are not available.

10)  The Jakarta Connector documents don't describe this, but I still choose to have a tomcat_jk.conf
and tomcat_jk_ssl.conf file, to be included in the http and https VirtualHosts section of httpd.conf,
as explained above.  However, there may be some different syntax in these files for JK2, since the
wonderful guys at Jakarta decided the old syntax wasn't good enough.  Here's what my new
tomcat_jk.conf file looks like:  (as always, you could put this directly in httpd.conf, instead of
Including it).

Alias /print "/opt/jakarta/tomcat/webapps/print"
<Directory "/opt/jakarta/tomcat/webapps/print">
    Options Indexes FollowSymLinks -Includes MultiViews
    Order Deny,Allow
    Allow from all
</Directory>
# The following location block is actually redundant with workers2.properties!
<Location "/print/*.jsp">
    JkUriSet group ajp13:localhost:8009
</Location>
# The following line prohibits users from directly accessing WEB-INF
<Location "/*/WEB-INF/">
    AllowOverride None
    deny from all
</Location>

This again defines the web application aliasing and Directory configuration properties.  It also
defines the worker connection properties to use for the *.jsp requests, which were defined in
workers.properties for the older mod_jk configuration.

11)  Also, you need a workers2.properties file, which bears no resemblance to the mod_jk
workers.properties file.   Here is mine.

You notice the URI mapping lines:
#Map the Tomcat examples to the web server uri space
[uri:/jsp-examples/*]

You can map the URI space with these lines, but since there is only one of these files, you need to map
all your URIs in this file, including those for http/normal and https/secure VirtualHosts. By default
this will make the JSPs available via both normal and secure web VirtualHosts, which may not be what you
want. You need to explicitly go into your httpd.conf section for each virtual host (which is what I use my
tomcat_jk.conf and tomcat_jk_ssl.conf files for), and explicitly allow and/or disallow each application.
This is because the workers2.properties file will map URIs to all Apache hosts. You could use lines like these
<Location "/print/*.jsp">
    JkUriSet group ajp13:localhost:8009
</Location>
in your tomcat_jk_ssl.conf (secure VirtualHost section). Unfortunately, if that's all you have, then that
Location has no access control. I thought I'd be cute, and add the "AuthType Basic", etc. sections to a
Location block like this, right after the JkUriSet directive. But unfortunately, the lame mod_jk2 code
sees the Jk mapping directive for a given Location, and it will dispatch the request to Tomcat, even if
the authentication fails! So, as far as I can tell, using the Location-JkUriSet method is only ok if
you have no need to specify special options for that Location. This makes it unusable for restricted JSPs.

12)  You should also check to make sure your settings are consistent with the jk2.properties
file that ships in the $CATALINA_HOME/conf directory.  View my file via the link here.

13)  Finally, you need to activate the Tomcat JK2 connector in the tomcat server.xml file
($CATALINA_HOME/conf/server.xml).  Here is a sample entry from my file:

    <!-- Define a Coyote/JK2 AJP 1.3 Connector on port 8009 -->
    <Connector port="8009"
               enableLookups="false" redirectPort="8443" debug="0"
               protocol="AJP/1.3" />

Now, you should be able to restart everything and get the two servers talking.  Hope this helps.


powered by Debian

Copyright ©2003-2016 Enscand, Inc.
All Rights Reserved

Modified February 21, 2016
Privacy
Security
Environment