Home > Support > HOWTO List > JSP Hosting: mod_proxy_ajp or mod_jk2 Apache Connectors

Accessing Tomcat on Port 80: From example.com:8080 to example.com

By default Tomcat and JBoss run on port 8080.  So your Tomcat urls look like http://example.com:8080/index.jsp.

There are a few ways ways you can access Tomcat webapps on the regular port 80 so that you do not need the port number in the URL.

Apache 2.2/2.4 mod_proxy

Often customers want to combine the use of JSP and Apache. For example, they may have some PHP scripts and some JSP programs they want to run. (And the Servlet engines cannot execute PHP scripts). Using Apache to handle your incoming requests also gives you more options for things like using SSL, error logs, and using .htaccess files.

Apache 2 introduces the mod_proxy module.  It is a standard module in most modern distros. This module pretty much deprecates the need for mod_jk2. Full Apache 2.2 and Apache 2.4 documentation for mod_proxy is available.

To setup mod_proxy_ajp add something like the following inside of your Apache VirtualHost entries (e.g. in /etc/httpd/conf/httpd.conf under CentOS/Fedora, /etc/apache2/sites-enabled under Ubuntu/Debian):

To forward all requests to http://yourip/tomcat to tomcat's ROOT webapp:

ProxyRequests off
ProxyPass /tomcat ajp://127.0.0.1:8009/
ProxyPassReverse /tomcat ajp://127.0.0.1:8009/

The ProxyPassReverse line helps to fix URLs returned by tomcat so they make sense on the Proxy context. Apache 2.4 extends this syntax to make it even more powerful.

Another example, to forward all requests to http://yourip/tomcat to tomcat's jsp-examples webapp.

ProxyPass /tomcat ajp://127.0.0.1:8009/jsp-examples

To forward all requests to http://yourip/ to tomcat's ROOT webapp:

ProxyPass / ajp://127.0.0.1:8009/

When apache is handleing SSL, if you use letsencrpyt add an exclusion line like the below. Note the exclusion falls *before* the main Proxy statements.

ProxyRequests off
ProxyPass /.well-known/acme-challenge !
ProxyPass / ajp://127.0.0.1:8009/
ProxyPassReverse / ajp://127.0.0.1:8009/

Also on Ubuntu/Debian systems, you may need to enable the specific proxy module for apache. One of the shell commands bellow as needed...

a2enmod proxy_ajp
a2enmod proxy_http

Resolving "client denied by server configuration"

If you get an error in the Apache error log like client denied by server configuration: proxy:ajp://127.0.0.1:8009/tomcat then you may need to enable Proxying.  e.g. on Ubuntu/Debian systems change the Proxy * setting from Deny all to Deny none in /etc/apache2/mods-enabled/proxy.conf:


        <Proxy *>
                AddDefaultCharset off
                Order deny,allow
                Deny from none
                #Allow from .example.com
        </Proxy>

Run the following to enable mod-proxy-ajp and to change allow/deny setting...

sed --in-place 's/Deny from all/Deny from none/' /etc/apache2/mods-available/proxy.conf

Prevent mod_proxy abuse as an open proxy.

The "ProxyRequests off" line is important, setting that to on will turn your server into an open proxy, which is not what you want. In some cases it is helpful to check across the entire apache configuration for cases where that may be present. Use something like the following snippet to find and fix those.

[[ -d /etc/httpd ]] && http_conf="/etc/httpd" || http_conf="/etc/apache2"
cd 
for file in $(grep -nR "ProxyRequests On" * | cut -d: -f1 ); do
  sed -i 's/ProxyRequests On/ProxyRequests Off/' ;
done

ajp and secrets

New installs of tomcat may disable the ajp connector by default. Once enabled you may need to add secretRequired="false" to allow ajp connections from apache. But do make sure in that case, tomcat is only listening on a trusted network (eg 127.0.0.1). It might look like this

<Connector protocol="AJP/1.3"
            address="127.0.0.1"
            secretRequired="false"
            port="8009"
            redirectPort="8443" />

If you have a very recent version of apache installed (2.4.41 or later) you could replace the secretRequired line above with "secret=yourphrase" in the connector, and add that to the ProxyPass line shown above for added security.

Running JSP Through Apache: mod_jk2

mod_jk2 is an option on Apache setups prior to Apache 2.2 (e.g. RHEL4, Debian 3.1).  It is not an option on newer setups (e.g. not on Centos5, FC5 or newer, Debian Etch, or Ubuntu 7.10).  For the newer distros you would use mod_proxy instead.

mod_jk2 intercepts Apache requests to certain URLs and forwards them to your Servlet engine.  For example, it can hand off requests to certain "mount points" like /jsp to your Servlet engine.  It can also hand off certain file types (e.g. *.jsp) to your Servlet engine.

mod_jk2 forwards the Apache requests to your Servlet engine via a socket using a protocol called ajp13.  Both Tomcat and Jetty support the ajp13 protocol.

First Step: Serve Content on Default Servlet Port

The first step towards running your webapps with Apache as a front end, is to first get them working directly from your default servlet eninge port.  8080 is the default port for Tomcat (including JBoss/Tomcat) and Jetty.  Taking this step before testing the mod_jk2 setup makes troubleshooting problems easier:

  1. Set up your web apps (you may use any of the installed Servlet engines, they all support mod_jk2).
  2. Make sure your can browse your webapp using a URL like: http://yourip:8080/jsp/index.jsp. When using Apache as a front end, it is best to not use a 'ROOT' mounted webapp.
  3. Do not run the iptables command to forward port 80 requests to the Servlet engine (since we want Apache to handle the incoming requests).
  4. Test you can load your web app on http://yourip/jsp/index.jsp

Note: your Servlet container needs to listen for connections from Apache.  The Tomcat and Jetty installations on RimuHosting VPSs are set up this way by default.  You just need to make sure they are running (see the Tomcat and Jetty start up instructions above).

Next Steps: Serving up your WebApp from Apache

RimuHosting have pre-installed the mod_jk2.so module binary for the Fedora, White Box Enterprise Linux 3 and recent Red Hat 9 distributions.  (If your Red Hat VPS was setup prior to 2004, contact support for information on how to get the mod_jk2.so module).

mod_jk2 is configured in the /etc/httpd/conf.d/mod_jk2.conf file.

This file includes a sample 'Location'.  It looks like this:


<Location "/jsp-examples">
  JkUriSet worker ajp13:localhost:8009
</Location>

This Location tag will direct requests to http://yourdomain/jsp-examples to the jsp-examples webapp (if one exists) on your Servlet engine.

If you want to run your own webapp instead, just edit this file and rename jsp-examples to your own webapp's name.  Alternatively you can add your own Location tags in /etc/httpd/conf/httpd.conf.

You can put the Location tag inside a VirtualHost tag if you want the Location to only work for a particular domain.  Note: on some servers there seems to be a problem where the VirtualHost is ignored, and the Location is used across all domains.  In this case you will need to setup a workers2.properties.

ROOT WebApps

If you want to have all requests go to Tomcat, use a Location of / and your requests will go to the Tomcat ROOT webapp.

If you want to mix and match Apache and Servlet engine requests for the domain, you may need to change the Location tag.  For example, set it to /*.jsp and /*.do.  This will make it so only the Servlet related requests go to the Servlet engine.

Tomcat Host Directive: When Each Domain Has Their Own Root Webapp

Do you have more than one domain and you want each domain to use a different root webapp?  Then you will need to use Tomcat Host directives so that Tomcat knows which webapp to serve for which domain.

Setup Apache VirtualHosts.  Then add a Location tag inside each of the VirtualHost directives in /etc/httpd/conf/httpd.conf, e.g.


<VirtualHost *:80>
ServerName yourdomain.com
ServerAlias *.yourdomain.com
<Location "/">
  JkUriSet worker ajp13:localhost:8009
</Location>
</VirtualHost>

In your server.xml file (usually /usr/local/tomcat/conf/server.xml) add something like:


<Host name="yourdomain.com"
appBase="/usr/local/tomcat/webapps">
<Context path="" docBase="webapp1" debug="0"/>
</Host>
<Host name="your2nddomain.com" appBase="/usr/local/tomcat/webapps">
<Context path="" docBase="webapp2" debug="0"/>
<Alias>www.your2nddomain.com</Alias>
</Host>

These directives setup the default webapps for each of the virtual hosts.

Then restart Apache and Tomcat.

Note: The server.xml changes are only required if you want to run multiple virtual hosts with different ROOT webapps.  If you just have multiple virtual hosts with uniquely named webapps, they are not required.  Just use the regular Location tags and make sure the webapp name and the Location directory match.

workers2.properties: When Location Tags Inside VirtualHost Directives Do Not Work

On some versions of mod_jk2 and Apache we have noticed a problem where Apache ignores the VirtualHost that a Location tag is nested within.  For example, a Location / inside one VirtualHost ends up applying to all VirtualHosts on the server.  So that all requests go to Tomcat, not just the requests for the intended domain.

To workaround this problem, remove your Location directives.  Create a /etc/httpd/conf/workers2.properties file. Then add directives like:

[uri:yourdomain.com:80/*]
worker=ajp13:localhost:8009
[uri:your2nddomain.com:80/*]
worker=ajp13:localhost:8009

These directives will pass the requests to the named virtual hosts to your Java server.  If you have yourdomain.com and www.yourdomain.com you'll need to add both those [uri] directives for each.

jk2_init Errors

Getting something like this in your apache error_log file?


[Mon Feb 04 15:36:04 2008] [error] jk2_init() Can't find child 9744 in none of the 256 scoreboard slots 

We have seen these errors before.  They do not appear to cause any problems.  And according to our googling can just be ignored.

IPTables: Forwarding Incoming Port 80 requests to Port 8080

If you want to use Apache as a front end to Tomcat, skip this section.

If you want to use iptables to forward incoming requests on port 80 to Tomcat on port 8080, run these commands to setup an iptable rule:

First, stop and disable apache. Under Centos or Fedora try the following...


# prevent Apache from running on startup
chkconfig --del httpd
# stop Apache from running right now
/etc/init.d/httpd stop

... or if you have Debian/Ubuntu based systems try ...


# prevent Apache from running on startup
update-rc.d -f apache2 remove
# stop Apache from running right now
/etc/init.d/apache2 stop

... then set the redirection up...


# install the iptables applications if they are not already there
apt-get -y install iptables
# tell iptables to forward incoming requests on port 80 to tomcat
/sbin/iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
# if you're not running it on the primary ip, then you'll need to specify that
# /sbin/iptables -A PREROUTING -d 74.50.60.197/32 -p tcp -m tcp --dport
80 -j DNAT --to-destination 74.50.60.197:8080

For RedHat/Fedora/CentOS based distros (if there is a file called /etc/redhat-release) use this:


# save the iptable rules
/sbin/iptables-save > /etc/sysconfig/iptables
# make sure iptables starts up by default after a server restart
chkconfig --level 35 iptables on

For Debian based distros (if there is a file called /etc/debian_version) use this:


# save the iptable rules
/sbin/iptables-save > /etc/firewall.conf
# create a script so ifupdown loads these rules on boot
echo '#!/bin/sh' > /etc/network/if-up.d/iptables
echo "iptables-restore < /etc/firewall.conf" >> /etc/network/if-up.d/iptables
chmod +x /etc/network/if-up.d/iptables

You may get a QM_MODULES warning.  You can safely ignore that.  Our VPS servers are built without modules and with the iptable features built into kernel itself.  The iptables scripts just do not detect that modules are not available and do not know to skip that step.

If you decide to turn off your iptables rules, run this:


iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables -t nat -F

For RedHat/Fedora/CentOS based distros (if there is a file called /etc/redhat-release) use this:


# save the iptable rules
/sbin/iptables-save > /etc/sysconfig/iptables
# make sure iptables starts up by default after a server restart
chkconfig --level 35 iptables off

For Debian based distros (if there is a file called /etc/debian_version) use this:


# save the iptable rules
/sbin/iptables-save > /etc/firewall.conf

Maintaining Java Sessions through an Apache Proxy

If your application makes use of Java Sessions, you may need to tweak the Cookie Path attribute to make it work as expected.  A common problem this might fix is when attempts to log in appear successful, but require you to log in again immediately.

The problem is that Java is sending a cookie path for a certain location, but Apache is configured to serve the application at a different location, so the browser receives the session cookie, but never sends it back because it never requests a page that matches the cookies location.

The original Set-Cookie header looks like this in the HTTP response

Set-Cookie: JSESSIONID=TOMCAT_SESSION_ID_HERE; Path=/myapp 

If your application is not accessible at /myapp though, it won't ever send that cookie back in a request, so you don't appear to have working sessions.  The solution is simple, but requires Apache 2.2 which introduced the ProxyPassReverseCookiePath setting with mod_proxy.  Add this line to your Apache configuration to have Apache rewrite the Path attribute in the Set-Cookie header:


    ProxyPass / ajp://127.0.0.1:8009/myapp/
    ProxyPassReverse / ajp://127.0.0.1:8009/myapp/
    ProxyPassReverseCookiePath /myapp /

That will change the path attribute in the Set-Cookie response header to this:

Set-Cookie: JSESSIONID=TOMCAT_SESSION_ID_HERE; Path=/

And now your browser will send the cookie back on requests to your application.