How to add mod_jk to Apache for Tomcat (+Railo!)

After finding out how I could use mod_jk for my Apache and Tomcat install, I found out that using mod_proxy does almost the same (it also uses AJP13). This last one is much more easy to setup, but it is only available for Apache 2.2 and later.

So here you will find the instructions for setting up mod_jk, even though I would suggest to just use the mod_proxy code if you are on Apache 2.2. I also included that setup underneath.

Prerequisites

You need to know and change a few variables:

  • {Apache-root}: this is the Apache install directory
  • What files do you want to be served by Tomcat? In the code underneath, I assume cfm and cfc files, which are the extensions for Coldfusion / Railo.
  • {Tomcat-root}: the Tomcat installation directory

Use mod_proxy if you have Apache 2.2 or later

In Apache's httpd.conf, you need to add the following:

# Tomcat for Railo configuration with proxy+ajp13:
<IfModule !proxy_module>
    LoadModule proxy_module {APACHE-ROOT}/modules/mod_proxy.so
</IfModule>
<IfModule !rewrite_module>
    LoadModule rewrite_module {APACHE-ROOT}/modules/mod_rewrite.so
</IfModule>
ProxyPreserveHost On
ProxyPassMatch ^/(.+\.cf[cm])$ ajp://localhost:8009/$1
ProxyPassMatch ^/(.+\.cf[cm])(/.*)$ ajp://localhost:8009/$1?path_info=$2
ProxyPassMatch ^/((flashservices/gateway|messagebroker/|flex2gateway/|openamf/gateway/).*) ajp://localhost:8009/$1

All Apache versions: Tomcat must be setup to handle AJP

The following xml must be available / has to be added in tomcat's /conf/server.xml:

<Server>
  [...]
  <Service name="Catalina">
    [...]
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Connect Apache 2.0 with Tomcat by using mod_jk

For Apache 2.0, AJP is only available via mod_jk. It can be quite easily configured, although it is more work to do.

In Apache's httpd.conf, you need to add the following:

# Load mod_jk module, if not yet loaded
<IfModule !jk_module>
LoadModule jk_module {APACHE-ROOT}/modjk/mod_jk.so
</IfModule>
# Where to find workers.properties
JkWorkersFile {APACHE-ROOT}/workers.properties
# Where to put jk shared memory
JkShmFile {APACHE-ROOT}/modjk/mod_jk.shm
# Where to put jk logs
JkLogFile {APACHE-ROOT}/modjk/mod_jk.log
# Set the jk log level [debug/error/info]
JkLogLevel error
# Select the timestamp log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# Send every request for .cfm and .cfc files to tomcat
JkMount /*.cfm worker1
JkMount /*.cfc worker1
# These SES links do not work on tomcat6 :-/
# JkMount /*.cfm/* worker1
# JkMount /*.cfc/* worker1
# Send every request for blazeDS to tomcat
JkMount /flashservices/gateway* worker1
JkMount /messagebroker* worker1
JkMount /flex2gateway* worker1
JkMount /openamf/gateway* worker1
## This setting makes sure that the above JK settings are propagated into all virtual hosts
JkMountCopy All

Tomcat must be configured for mod_jk

The following xml must be available / has to be added in tomcat's /conf/server.xml:

<Server>
  [...]
  <Service name="Catalina">
    [...]
    <Engine name="Catalina" defaultHost="localhost">
      <Listener className="org.apache.jk.config.ApacheConfig"
        modJk="{APACHE-ROOT}/modjk/mod_jk.so"
        workersConfig="{APACHE-ROOT}/workers.properties"/>

Create the directory {Apache-root}/modjk/

Necessary for the config files for mod_jk, and the module itself. It looked handy to me to put all the mod_jk stuff in one directory.

Create the workers.properties file

Create a file called "workers.properties" in the Apache root directory, with the following content:

workers.tomcat_home={TOMCAT-ROOT}
workers.java_home={PATH-TO-JAVA-INSTALLATION} (i.e. the Railo jre directory?)
worker.list=worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009 (THIS PORT MUST MATCH THE TOMCAT SETUP)

If you haven't got a java installation already, you can download and install the latest jdk from sun.com (make sure you choose the JDK version)

Add the mod_jk.so module to the Apache install

Since this module is not part of the default Apache install, you need to download a compiled version here: http://tomcat.apache.org/download-connectors.cgi
If you are running on mac OSX 10.6 like me, then I already compiled the module for you :-)

Done!

When you now restart Apache and Tomcat, everything should work! if it doesn't, then take a log at the log files:

  • {APACHE-ROOT}/logs/ (or another log location; see your httpd.conf for that)
  • {TOMCAT-ROOT}/logs/catalina.out (and other logs)
  • Or first stop Apache, and then enter the following command in a console window:
    • Windows: {apache-root}/bin/httpd.exe start -e debug
    • Mac: sudo apachectl -k start -e debug
  • {APACHE-ROOT}/modjk/*.log

Good luck with it!

del.icio.us Digg StumbleUpon Facebook Technorati Fav reddit Google Bookmarks
| Viewed 11626 times
  1. Erik-Jan Jaquet

    #1 by Erik-Jan Jaquet - October 30, 2010 at 4:56 PM

    Hi Paul,

    I read the posting and followed it to make Railo/Tomcat work on my Macbook. Worked like a charm, thanks for that! The only problem I have now, is trying to get some of my projects that need SES url's to work.

    I use the default Apache rewrite module, on Tomcat 5. My pages where the index.cfm is missing (for instance, not /index.cfm?Event=contact.home but /contact/home/) are redirected to Tomcat, but Tomcat throws a 404.

    Got any experience getting this to work? It is the last missing piece of the puzzle!

    Kind regards,

    Erik-Jan
  2. Paul Klinkenberg

    #2 by Paul Klinkenberg - October 30, 2010 at 5:58 PM

    Hi Erik-Jan, great to be commenting in English, so everybody can understand! (we're both Dutch)
    I guess you should use a 404 handler in Apache, which redirects all non-existing paths to your index.cfm. Then, in index.cfm, you can check for cgi.redirect_url and cgi.redirect_query_string, as I blogged about here: http://www.railodeveloper.com/post.cfm/getting-cgi-redirect-url-in-railo-on-tomcat-and-apache-404-redirects
    In that blog post, I said that these cgi vars aren't available in Railo, but that bug ticket is already resolved for version 3.2.0.001: https://jira.jboss.org/browse/RAILO-1006

    Or do you mean that there IS an index.cfm in the directory /contact/home/? In that case, you need to change the "welcome files" in tomcat to include "index.cfm". But I guess you would understand that already ;-)
    Paul
  3. Erik-Jan Jaquet

    #3 by Erik-Jan Jaquet - October 30, 2010 at 6:23 PM

    Hi Paul,

    No, there is no directory named contact. I use a rewrite rule to be able to remove the index.cfm from the url. The rest of the url contains only key/value pairs. The Application is a Coldbox Application, so all request go through index.cfm in the root. The rewrite rule works great on my server which uses resin, but for some reason fails on Tomcat...
  4. Paul Klinkenberg

    #4 by Paul Klinkenberg - October 30, 2010 at 6:50 PM

    Can you show me the rewriterule in question?
    If it is something like RewriteRule ^/([^/]+)/([^/\.]+)/?$ /index.cfm?Event=$1.$2, then I guess it should just work.
    Is the rewriterule inside the [Virtualhost] container on Apache? And what's the error that tomcat is giving?
    You could also try to debug the rewriting, by adding a RewriteLog and RewriteLogLevel line in the Apache conf.
  5. Erik-Jan Jaquet

    #5 by Erik-Jan Jaquet - October 30, 2010 at 8:27 PM

    Hi Paul,

    The rewrite rule seems to produce the right output: the url /laptop.html is being redirected to /index.cfm/laptop.html according to the logs. That is what needs to be done, and Coldbox should be able to do the rest. This is the entry in the log file: internal redirect with /index.cfm/laptop.html [INTERNAL REDIRECT]
    And this is my redirect rule:
    #The ColdBox index.cfm/{path_info} rules.
    RewriteRule ^$ index.cfm [QSA]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.cfm/%{REQUEST_URI} [QSA,L]
  6. Paul Klinkenberg

    #6 by Paul Klinkenberg - October 30, 2010 at 9:23 PM

    Hi Erik-Jan, SES links are not supported by tomcat at all. I thought you already understood that :-/ That is why I created the ProxyPassMatch "^/(.+\.cf[cm])(/.*)$ ajp://localhost:8009/$1?path_info=$2".
    What you can do, is change the index.cfm to check "url.path_info" instead of the cgi one, and then change your rewriterule to "index.cfm?%{REQUEST_URI} [QSA,L]"
    Hope it helps, Paul
  7. Paul Klinkenberg

    #7 by Paul Klinkenberg - October 30, 2010 at 10:23 PM

    Hi Erik-Jan, while doing the dishes, I thought of something else... If all your ses-links are going to /index.cfm, then you can fix it by adding a servlet-mapping to tomcat. Open the file {tomcat-install}/conf/web.xml, duplicate "[servlet-mapping] [servlet-name]RailoCFMLServlet[/servlet-name] [url-pattern]*.cfm[/url-pattern] [/servlet-mapping]", and change "*.cfm" to "/index.cfm/*". That should do the trick I guess :-)
  8. Samer Gad

    #8 by Samer Gad - September 7, 2011 at 8:06 AM

    Hi Paul,

    I'm Samer Gad, technical architect and J2EE developer with 7 years experience and I'm pretty new in the CF field.

    Sorry, for replying to an old post; I found it very useful but I need a technical clarification regarding the SES URLs, currently I'm working on an existing project which is running on Adobe ColdFusion8 + JRun (The default installation) and I'm preparing to move it to JBoss (and JBoss Web which is a Tomcat based Web Container) and Apache HTTPD, anyway I have two major issues as follows:

    1- Adobe ColdFusion and JRun has a ready made Apache connector which tells JRun about the web-root and virtual-hosting every request, and I'm not able to do the same for Tomcat through MOD_PROXY or even MOD_JK.

    2- Tomcat doesn't support wildcard Servlet mapping, and so I can't enable the SES URLs, as I can't use "*.cfm/*" mapping technique. And we are using SES URLs extensively and parse them to extract URL parameters, and we use the following format: "http://www.example.com/whatever.cfm/id1234";. The solution is a result of 10 years continuous work so it's not an easy task to refactor all places that use SES.

    Please advice!

    Thanks in advance,
    Samer Gad
  9. Paul Klinkenberg

    #9 by Paul Klinkenberg - September 7, 2011 at 10:07 AM

    Hi Samer,

    Adobe CF/Jrun has a so-called "magic connector". I have been spending a lot of time last year trying to create something like that for Railo as well, and in the end came up with a VHost copier (http://www.railodeveloper.com/post.cfm/apache-iis-to-tomcat-vhost-copier-for-railo). It's nothing like the magic connector, but it's a start.

    What you need to do, is setup your hosts both in Apache and Tomcat. The VHost copuer can add the hosts from Apache directly into Tomcat (some situations aside).

    The wildcard servlet mapping is indeed a major problem. I *really* don't understand why the tomcat folks didn't bake this in; it's pretty common nowadays.
    You could do:
    - add servlet mappings in tomcat for each ses cfm page: /whatever.cfm*, /another.cfm* etc.
    - do a rewrite-rule in apache which changes /whatever.cfm/bla into /whatever.cfm?path_info=bla
    - run all your pages from the 404 page.

    Option 1 is much preferred, but then you shouldn't have too much cfm pages with ses urls.
    Otherwise, go for option 2.
    Option 3 is a last resort, as it will give you wrong info in server-side statistics (e.g. 100% of calls are 404's), and some of the cgi variables like cgi.script_name will point to your 404 page, which makes it unusable for the rest of your app (e.g. forms which post to cgi.script_name).

    Hope this helps!

    If you need more assistance, I'd be more then happy to give you an estimate if you can tell me which way you want to go in getting this going.

    Kind regards, Paul
(will not be published)
Leave this field empty

leash-environment