This article contains step by step instructions for configuring an Apache web server which handles static content and delegates JSP (Java Server Pages) and Servlet requests to two Tomcat servers using AJP 13 connectors and a load balancing worker.
Apache 2.0 is a standards compliant, fast and mature web server which excels at delivering static content such as static HTML pages and images. The Tomcat web server is great for serving Java Server Pages and servlets, but it is not as fast as Apache for delivering static content.
In order to build a fast, scalable web application, the requirements call for an Apache server that delegates servicing of JSP and servlet requests to multiple tomcat servers by using an Apache module, mod_jk, that performs load balancing with session affinity, also known as “sticky” sessions.
Session affinity explained. When a client browser requests a JSP page for the first time, the load balancer redirects the request received by Apache to one of the two tomcat servers; further requests originating from the same client session will be automatically forwarded to the same tomcat server, so that the user’s session data is retrieved.
This document describes how I configured Apache 2.x to dispatch JSP and servlet requests to two Tomcat 4.x instances listening on different ports. This setup was done on a Linux system. Your mileage may vary.
Download the required software
Apache 2.x Binaries (If you plan to use ssl, get the source) Tomcat 4.x Binaries The JK module
Compile, Install and Configure Apache
Linux: gunzip the *.gz you downloaded, untar and run install-bindist.sh
For *nux, to install Apache 2.0.42 with mod_sll installed, you will need to compile from source: I used http://httpd.apache.org/docs-2.0/install.html as a reference.
$ lynx http://archive.apache.org/dist/httpd/httpd-2.0.42.tar.gz $ gzip -d httpd-2.0.42.tar.gz $ tar xvf httpd-2.0.42.tar $ ./configure –enable-mods-shared=most –enable-ssl=shared $ make $ make install
Then download mod_jk-2.0.42.so and put it into your modules directory and rename it mod_jk.so.
Windows: Execute the downloaded executable and install.
Configure the JK Module in httpd.conf
Edit the Apache server’s configuration file httpd.conf which is located in the /usr/local/apache2/conf directory.
Below “# LoadModule foo_module modules/mod_foo.so”, insert the following lines:
# # Load mod_jk # LoadModule jk_module modules/mod_jk.so # # Configure mod_jk # JkWorkersFile conf/workers.properties JkLogFile logs/mod_jk.log JkLogLevel info
NOTE: You will need to change mod_jk.so to mod_jk.dll for Windows.
Below the “DocumentRoot” line, insert the following two lines:
JkMount /*.jsp loadbalancer JkMount /servlet/* loadbalancer
Create the workers.properties file
Now we will create a file called worker.properties, and we will place it under /usr/local/apache2/conf. The worker.properties file tells Apache about the various Tomcat servers that are running, and on which port they are listening.
In my setup, I installed the two Tomcat servers in different directories, on the same machine as Apache. Feel free to put your Tomcat servers on different machines.
I made the first Tomcat server’s AJP13 connector listen on port 11009 instead of the default port which is 8009, and the second one listens on port 12009.
I have decided to name my tomcat servers tomcat1 and tomcat2. This is purely my choice.
Create the file exactly like this:
# # workers.properties # # In Unix, we use forward slashes: ps=/ # list the workers by name worker.list=tomcat1, tomcat2, loadbalancer # ------------------------ # First tomcat server # ------------------------ worker.tomcat1.port=11009 worker.tomcat1.host=localhost worker.tomcat1.type=ajp13 # Specify the size of the open connection cache. #worker.tomcat1.cachesize # # Specifies the load balance factor when used with # a load balancing worker. # Note: # ----> lbfactor must be > 0 # ----> Low lbfactor means less work done by the worker. worker.tomcat1.lbfactor=100 # ------------------------ # Second tomcat server # ------------------------ worker.tomcat2.port=12009 worker.tomcat2.host=localhost worker.tomcat2.type=ajp13 # Specify the size of the open connection cache. #worker.tomcat2.cachesize # # Specifies the load balance factor when used with # a load balancing worker. # Note: # ----> lbfactor must be > 0 # ----> Low lbfactor means less work done by the worker. worker.tomcat2.lbfactor=100 # ------------------------ # Load Balancer worker # ------------------------ # # The loadbalancer (type lb) worker performs weighted round-robin # load balancing with sticky sessions. # Note: # ----> If a worker dies, the load balancer will check its state # once in a while. Until then all work is redirected to peer # worker. worker.loadbalancer.type=lb worker.loadbalancer.balance_workers=tomcat1, tomcat2 # # END workers.properties #
That’s it, we’re done with Apache.
Install and Configure the Tomcat Servers
Now let’s suppose that Java 1.4.x is installed under /usr/local/jdk1.4.x/. Create two Tomcat 4.x servers and install them under /usr/local/:
tar fvxz jakarta-tomcat-4.x.tar.gz mv jakarta-tomcat-4.x /usr/local/tomcat1 cp -R /usr/local/tomcat1 /usr/local/tomcat2
In both /usr/local/tomcat1 and /usr/local/tomcat2, the same files will be modified. I here by present the modifications made to the files contained in the /usr/local/tomcat1 directory tree structure. You should also apply the same changes to the corresponding files located under the /usr/local/tomcat2 directory tree structure.
In my many years of consulting, I have learned not to rely on environment variables which can be unset by ignorant or malicious people. This is why I explicitely set the JAVA_HOME and CATALINA_HOME variables directly in the catalina.sh file.
At line 32, before the “# —– Verify and Set Required Environment Variables ” line, insert the following two lines:
JAVA_HOME=/usr/local/jdk1.4 ; export JAVA_HOME CATALINA_HOME=/usr/local/tomcat1 ; export CATALINA_HOME
(Set CATALINA_HOME to /usr/local/tomcat2 in /usr/local/tomcat2/conf/catalina.sh)
Add a unique jvmRoute to the Catalina engine
Near line 100, replace:
<Engine name="Standalone" defaultHost="localhost" debug="0">
<Engine jvmRoute="tomcat1" name="Standalone" defaultHost="localhost" debug="0">
For tomcat2, put jvmRoute=”tomcat2″.
Change the control port
At line 13, replace:
For the tomcat2 server, replace port 8005 with 12005. This will prevent the two servers from conflicting.
Change the AJP13 port
At line 75, in the AJP 13 connector definition, replace:
For the tomcat2 server, replace port 8009 with 12009.
Disable the standalone HTTP port
We don’t want or need our tomcat servers to directly respond to HTTP requests. So we comment out the HttpConnector section between lines and 58 in the server.xml file.
NOTE: If you don’t comment this out, you will need to change the port numbers so they don’t conflict between tomcat instances.
Disable the WARP connector
At line 314, comment out the <Connector…WarpConnector…> tag.
Do not forget to do the same thing to tomcat2’s server.xml file.
NOTE: You might want to comment out the entire <Service name=”Tomcat-Apache”> element. If so, make sure and remove the comments within it – XML doesn’t like comments within comments.
Create test JSP pages (index.jsp)
Create a file named index.jsp and put it in the /usr/local/tomcat1/webapps/ROOT directory:
<html> <body bgcolor="red"> <center> <%= request.getSession().getId() %> <h1>Tomcat 1</h1> </body> </html>
Create a file named index.jsp and put it in the /usr/local/tomcat2/webapps/ROOT directory:
<html> <body bgcolor="blue"> <center> <%= request.getSession().getId() %> <h1>Tomcat 2</h1> </body> </html>
Start Tomcat1, Tomcat2 and Apache
/usr/local/tomcat1/bin/startup.sh /usr/local/tomcat2/bin/startup.sh /usr/local/apache2/bin/apachectl start
Test your Installation
Now is the time to test your setup. First, verify that Apache serves static content.
Click on: http://localhost/. You should see the default Apache index.html page.
Now test that tomcat (either Tomcat 1 or Tomcat 2) is serving Java Server Pages.
Click on: http://localhost/index.jsp
If you get a red page, the page was served by the tomcat1 server, and if you get a blue page, it was served by the tomcat2 server.
Now test that session affinity – also known as sticky sessions – works within the load balancer. Hit the reload button of your web browser several times and verify that the index.jsp page you get is always received from the same tomcat server.
Configuring Private JVMs
If you don’t need load-balancing, but you are interested in configuring Apache/Tomcat for private Tomcat instances, you can add one of the following near the end of httpd.conf:
Name-based (1 IP address or NIC).
NameVirtualHost * <VirtualHost *> ServerName localhost1 JkMount /*.jsp tomcat1 JkMount /servlet/* tomcat1 </VirtualHost> <VirtualHost *> ServerName localhost2 JkMount /*.jsp tomcat2 JkMount /servlet/* tomcat2 </VirtualHost>
IP-based (different IP for each site).
# First Virtual Host. # <VirtualHost 192.168.0.1:80> ServerName localhost JkMount /*.jsp tomcat1 JkMount /servlet/* tomcat1 </VirtualHost> # Second Virtual Host. # <VirtualHost 192.168.0.2:80> ServerName localhost2 JkMount /*.jsp tomcat2 JkMount /servlet/* tomcat2 </VirtualHost>
Where the serverNames are fully-qualified host names in a DNS Server. More information can be found at http://httpd.apache.org/docs-2.0/vhosts/.
NOTE: When using SSL with multiple Virtual Hosts, you must use an ip-based configuration. This is because SSL requires you to configure a specific port (443), whereas name-based specifies all ports (*). You might the following error if you try to mix name-based virtual hosts with SSL.
[error] VirtualHost _default_:443 — mixing * ports and non-* ports with a NameVirtualHost address is not supported, proceeding with undefined results
Starting Apache and Tomcat on Startup To start Apache and Tomcat on startup in a *nix environment, see http://www.raibledesigns.com/tomcat/boot-howto.html.
On Windows, you can install Tomcat as a service.
For more information, you should read An Apache Load Balancing Cluster. It talks about mod_jserv, which is now mod_jk, and it uses JServ instead of Tomcat, but the concepts are still valid.
The list of steps that are required to obtain a scalable web application solution based on Apache 2.x and a group of distibuted Tomcat servers are well-defined and if you follow the receipe exactly, you should be able to achieve success.
I hope that this article will be helpful to you. Good Luck.