How can I set use mod_proxy_ajp with Apache and Tomcat?

I'd like to run Apache and Tomcat on an RHEL 5 server with Apache handling Ruby on Rails apps (through mod_rails/Passenger) and Tomcat handling Java apps.

Under Apache, each Rails app will have a URL and vhost. The URLs are already configured in our DNS server to point to the machine.

Under Tomcat, each Java app has a URL like this: ourserver.ourcompany.com/app1, ourserver.ourcompany.com/app2, etc.

The server is already up and running with Tomcat 6 running on port 80 and serving several Java apps. I want to add Apache and reconfigure. I'm familiar with how to configure a sole Apache server to host RoR apps using Passenger. I just don't know how to get Apache and Tomcat to work together like that.

I've found various resources and discussions through Googling (for example, this one) but they tend to be a bit sketchy and incomplete or they don't seem to really match what I'm trying to do. The one I linked to seems to be for if you want to send all requests to Tomcat, not just certain ones and have Apache handle others.

Could someone suggest an example config for server.xml and httpd.conf, or perhaps point me to some resources that are more detailed?


Solution 1:

You shouldn't need to make any changes to the server.xml except to put Tomcat back to the default ports so Apache can handle port 80. The bulk of the work will be done through the Apache configuration files. I typically leave these outside of the httpd.conf and instead stick them into smaller config snippets under the <ServerRoot>/conf.d/ sub-directory.

Given your example of ourserver.ourcompany.com/app1 & ourserver.ourcompany.com/app2 I would I would assume a configuration something along the following:

<VirtualHost *:80>
    ServerName ourserver.ourcompany.com
    ErrorLog ...
    CustomLog ...

    [other VHost configurations]

    ProxyPass /app1 ajp://tomcat_hostname:8009/app1
    ProxyPassReverse /app1 ajp://tomcat_hostname:8009/app1

    ProxyPass /app2 ajp://tomcat_hostname:8009/app2
    ProxyPassReverse /app2 ajp://tomcat_hostname:8009/app2
</VirtualHost>

If you have multiple Tomcat servers clustered behind then you might want to look at setting up mod_balancer and moving the ajp:// to mod_balancer BalancerMember's and replace with the balancer:// URL that refers to the balancer configuration.

Solution 2:

I don't like mod_proxy_ajp personally; when running Tomcat under Apache I go right to installing mod_jk (the module from Tomcat coders) to provide the AJP connection. You can tune mod_jk 5 ways to Sunday for performance of your apps (threads, timeouts, knocks, etc.).

  1. Make sure httpd-devel is installed
  2. Unpack the real JDK to some path, like /usr/local/jdk1.6.0_18/
  3. grab the "tomcat-connectors" source from tomcat.apache.org and compile it

    cd tomcat-connectors-1.2.28-src/native

    ./configure --with-apxs=/usr/sbin/apxs --with-java=/usr/local/jdk1.6.0_18 --enable-prefork

    make

    cp apache-2.0/mod_jk.so /usr/local/lib/

Now you have to plug it into your Apache config in a general sense, then into each virtual host as appropriate. In the overall config you add something like:

LoadModule jk_module /usr/local/lib/mod_jk.so
JkWorkersFile  /usr/local/tomcat/conf/workers.properties
JkShmFile      /var/log/httpd/mod_jk.shm
JkLogFile      /var/log/httpd/mod_jk.log
JkLogLevel     error

You will need to create the basic worker.properties file, here's the docs: http://tomcat.apache.org/connectors-doc/reference/workers.html A very basic one might look like this:

workers.tomcat_home=/usr/local/tomcat
workers.java_home=/usr/local/jdk1.6.0_18
ps=/
worker.list=ajp13
worker.maintain=60
worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=ajp13

This will use the default port 8009 config from server.xml - there's a million knobs you can twiddle here to performance tune endlessly. Then, in each virtual host you "mount" the app(s) you want:

<VirtualHost *:80>
 ServerName foo.bar.com
 ...other options ...

 JkMount /app1/* ajp13
 <Location "/app1/WEB-INF/">
    deny from all
 </Location>

 JkMount /app2/* ajp13
 <Location "/app2/WEB-INF/">
    deny from all
 </Location>

</VirtualHost>

As you see at the bottom there, don't forget a little security and deny all access to your WEB-INF folder -- most webapps have their database DSN with password web.xml when deployed as a warball.