Configuring an Apache VirtualHost to use Tomcat

I was talking to a friend who asked about configuring an Apache virtual host to use Tomcat. I have Apache httpd 2.2.8 running on port 80 and tomcat 5.5.26 running on port 8080 on Windows XP Pro. So the following worked for me:

http://server/ <– handled by Apache

http://server:8080/ <– handled by Tomcat

At first, I didn’t quite understand what he was saying. I thought he wanted something like this:

http://server/ <– to be handled by Apache
http://server/tomcat/
<– to be handled by Tomcat
http://server/any/other/path <– to be handled by Apache

He said he didn’t care about the port 8080 being displayed, so could just use mod_rewrite?

Here’s the rule I came up with, and added to httpd.conf:

RewriteEngine On
RewriteRule ^/tomcat/(.*) http://server:8080/$1

So whenever somone types the following url http://server/tomcat/foo they get a rewritten URL displayed as http://server:8080/foo handled by tomcat. They can continue to navigate relative URLs as long as they stay within the http://server:8080/ domain. Any URL with http://server/ (without port 8080 in the URL) will still be handled by Apache. So will any URLs starting with http://server:80/

This is the simplest possible solution.

I then found out that what he actually wanted was to use one server (OS) to host two domains, one using Apache and the other Tomcat. This was easy enough to solve by creating two virtual hosts, one for each server.

http://apache/ <– handled by Apache
http://tomcat/ <– handled by Tomcat

First, I needed to create the hosts. He was using a registered domain, but I just both to my /etc/hosts file (actually C:\WINDOWS\System32\drivers\etc\hosts):

127.0.0.1 localhost apache tomcat

Do whatever you need to do to make it resolve.

First I created two Apache config files, one for each virtual host. I added the rewrite rule to only the tomcat vhost.

C:/apache/conf/vhosts/apache.conf

<VirtualHost 127.0.0.1:*>

ServerName apache
DocumentRoot “C:/Apache/htdocs”

<Directory />
Options All
Order deny,allow
Allow from all
</Directory>

</VirtualHost>

C:/apache/conf/vhosts/tomcat.conf

<VirtualHost 127.0.0.1:*>

ServerName tomcat
DocumentRoot “C:/Apache/htdocs”
RewriteEngine On
RewriteRule ^/(.*) http://apache:8080/$1

<Directory />
Options All
Order deny,allow
Allow from all
</Directory>

</VirtualHost>

I added the following to my httpd.conf, so that they would be included.

include “C:/Apache/httpd/2.2/conf/vhosts/*.conf”

Also make sure you have the following in httpd.conf to handle virtual hosts on the correct IP

NameVirtualHost 127.0.0.1:*

and that mod_rewrite is enabled.

I restarted Apache and everything was working. Requests to http://apache/ get handled by Apache,

and requests to http://tomcat/ get rewritten to http://tomcat:8080/ and then handled by Tomcat.

I then created exceptions to the rules, so that requests to http://tomcat/exception/* are handled by Apache and requests to http://apache/tomcat/* are handled by Tomcat.

I added the following to apache.conf:

RewriteEngine On
RewriteRule ^/tomcat/(.*) http://apache:8080/$1

and added to tomcat.conf (placed before the other RewriteRule):

RewriteRule ^/exception – [L]

This is simple enough. But what if we didn’t want the port number displayed? (Or any other rewrite confusion?)

Apache httpd server is commonly used as a proxy in front of tomcat or other servers. My friend said he’d heard about a module that handles this. There are in fact several approaches, some of which are out of date.

The original (to my knowledge) was mod_jserv. This is out of date. For a while, the two common methods (that I know of) were mod_jk and mod_proxy. The first ended up being faster because it used a binary protocol, AJP (Apache JServ Protocol), but was more difficult to configure. Another module, mod_jk2 was create with the goal of making that easier. This has since been deprecated in favor of the original mod_jk (currently at version 1.2.6). A newer module that is available, only for Apache 2.2 is mod_proxy_ajp. It uses a proxy, but also uses the AJP binary protocol, so is faster, and keeps open connections between Apache and tomcat. This would possibly be the best of both worlds, but is newer, and is doesn’t have some of the advanced features that mod_jk has. Load balancing and https are two issues that apparently mod_jk handles better than mod_proxy. It also has some additional management and error reporting. Also, I think large request sizes (more than 8k) can be handled by mod_jk (but only up to 64k), but not mod_proxy_ajp . This may have been fixed already.

Here are some links:

http://tomcat.apache.org/connectors-doc/

http://httpd.apache.org/docs/2.2/mod/mod_proxy_ajp.html

http://directwebremoting.org/blog/joe/2006/02/01/mod_jk_is_dead_long_live_mod_proxy_ajp.html

http://blogs.jboss.com/blog/mturk/2007/07/16/Comparing_mod_proxy_and_mod_jk.txt

http://www.mail-archive.com/users@tomcat.apache.org/msg03570.html

http://anilsaldhana.blogspot.com/2006/04/modjk-versus-modproxy.html

http://confluence.atlassian.com/display/DOC/Running+Confluence+behind+Apache

Here’s how I set it up to work on my localhost.

I created the following hosts:

127.0.0.1 localhost apache tomcat modjk modproxyajp

(okay, I actually set up apache.ae tomcat.ae modjk.ae modproxyajp.ae, but deleted the ‘.ae’ from this example for clarity.)

I downloaded mod_jk from here. The latest version is for Apache 2.2.4, but I haven’t seen a problem. I renamed it to mod_jk.so and copied it to my Apache modules directory.

C:\Apache\modules\mod_jk.so

Then I added to following to my httpd.conf (so that I can reference mod_jk outside the vhost):

LoadModule jk_module modules/mod_jk.so
JkWorkersFile “C:/Apache/conf/workers.properties”
JkLogFile “C:/Apache/logs/mod_jk.log”
JkLogLevel info
JkOptions +ForwardURICompatUnparsed

Next I created the workers.properties file referred to in my httpd.conf:

C:/Apache/conf/workers.properties

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

I then set up a vhost for modjk:

C:/Apache/conf/vhosts/modjk.conf

<VirtualHost 127.0.0.1:*>
ServerName modjk
DocumentRoot “C:/Tomcat/webapps/”
JkMount /* worker1
</VirtualHost>

The JKMount directive says that every URL (/*) is handled by the jk worker1. You can create multiple workers and specify then in your tomcat server.xml config file. This is included by default in mine:

<Connector port=”8009″ enableLookups=”false” redirectPort=”8443″ protocol=”AJP/1.3″ />

After restarting Apache, now, when I go to http://modjk I get the Tomcat homepage:

I also added the following to my original apache.conf so that I can reference mod_jk from a certain directory:

C:/Apache/conf/vhosts/apache.conf

<VirtualHost 127.0.0.1:*>

ServerName apache
DocumentRoot “C:/Apache/htdocs”

RewriteEngine On
RewriteRule ^/tomcat/(.*) http://apache:8080/$1

<Directory />
Options All
Order deny,allow
Allow from all
</Directory>

JkMount /modjk/* worker1

</VirtualHost>

When I go to http://apache/modjk/ it uses Tomcat, but I get a 404, because my path is messed up. I either need to specify the document root for the <Location /modjk> or have Tomcat expect this path.

TODO: fix this.

Then I tried out mod_proxy_ajp. It’s already included with Apache 2.2, so I didn’t need to download anything. I created the following vhost config file:

C:/Apache/conf/vhosts/modproxyajp.conf

<VirtualHost 127.0.0.1:*>
ServerName modproxyajp

DocumentRoot “C:/tomcat/webapps/”

ProxyRequests Off

<Proxy *>
Order deny,allow
Allow from all
</Proxy>

ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/

<Location />
Order allow,deny
Allow from all
</Location>

</VirtualHost>

Notice the ProxyPass, which is kind of like a rewrite, but it also specifies the ajp:// protocol. If Tomcat were on a different server than Apache, you’d specify the hostname instead of localhost. Port 8009 is the default, and you’ll remember that it’s set for the tomcat connector in server.xml

Now I can restart Apache and go to http://modproxyajp/ and it serves Tomcat (which is actually running on port 8080) through Apache (on port 80), using the AJP binary protocol from mod_jk, but via the built-in AJP proxy.

I also edited my original apache.conf to be able to server mod_proxy_ajp from that host as well.

<VirtualHost 127.0.0.1:*>

ServerName apache
DocumentRoot “C:/Apache/htdocs”

<Directory />
Options All
Order deny,allow
Allow from all
</Directory>

# use mod_rewrite to forward directly to tomcat on port 8080
RewriteEngine On
RewriteRule ^/tomcat/(.*) http://apache:8080/$1

# use mod_jk to forward to tomcat
JkMount /modjk/* worker1

# use mod_proxy_ajp to forward to tomcat
ProxyPass /modproxyajp ajp://localhost:8009/

ProxyPassReverse /modproxyajp ajp://localhost:8009/

</VirtualHost>

I restarted Apache once again and typed http://apache/modproxyajp/ into my browser.

I don’t know whether mod_jk or mod_proxy_ajp is better. My guess is it depends on your definition of “better.” Mod_jk has the advantage of being older, and Mod_proxy_ajp has the advantage of being built in. For simple uses, either appear fine.

I haven’t got into any details about load balancing or complex management or session issues because I don’t know enough about it yet. If there’s a demand, I might post a follow up.

Advertisements

8 thoughts on “Configuring an Apache VirtualHost to use Tomcat

  1. One thing I didn’t check is that my modjk and modproxyajp vhosts have C:/tomcat/webapps/ as their DocumentRoot. So it’s possible that it’s serving the Tomcat index directory. Though I don’t think so. I believe it only has index.jsp, so if Apache were serving it, it wouldn’t render properly. When testing earlier, I believe among other things, that it didn’t render the tomcat logo image properly when served as static HTML.

  2. I realize that calling the httpd server “Apache” and the Tomcat server “Tomcat” could be confusing for some, because “Tomcat” is a project sponsored by the Apache Software foundation.

    I referred to them this way for clarity and simplicy.

  3. I’d hoped that the screenshot images would be just big enough to read the address bar. It turns out that it’s just small enough to be illegible.

    The idea was to show the URLs (and proof) so that you could tell what is displayed to the user after typing in the URL as described above each image.

    Sorry. If I ever get the time, I’ll try to replace them.

  4. Another test I could do is to try the example webapps and jsps. But my installation didn’t have them, and I didn’t feel like getting them. For modjk at least I tried another webapp that worked fine, but I didn’t post a screenshot of it here.

  5. Hi,came across your post and came across a similar situation and wondering if you could help out.. first question though is that when i use your quick and easy solution of using rewritewnginge on, my apache services does not start. just throws a failure message

    • First thought — did you try turning it off and…
      I mean is mod_rewrite enabled?

      In most cases these days you probably just want to enable mod_proxy and do


      <Location /tomcat>
      ProxyPass /webapp localhost:8080
      ProxyPassReverse /webapp localhost:8080
      </Location>

      or


      <VirtualHost *:80>
      ServerName tomcat
      ProxyPass / localhost:8080
      ProxyPassReverse / localhost:8080
      # ...
      </VirtualHost *:80>

      Thanks to Rails & Python frameworks mod_proxy does a pretty good job nowadays, but you can also use mod_proxy_ajp for reasons described above.

      If you give me more details about what you’re trying to accomplish I’d be happy to try to help you out more.

  6. hi there ,

    i need to integrate the apache web serer and tomcat server using with connector mod_jk can you please give a procedure in windows ..

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s