Configuring Tomcat5 and Apache2 to run with multiple instances

This describes the process for configuring Tomcat 5 on Ubuntu (or Debian) so that you can have multiple instances of Tomcat running. Typically, this would be useful when you have several domains (and/or applications) hosted on the one server and want to keep them running independantly of one another.

The general steps are based loosely on an article in LinuxJournal, however, I have added afew more explanations, corrected a couple of little inaccuracies and added new content to describe the Apache2 mechanism for loading modules and sites.

Pre-installed software

This guide assumes that you have already installed the following applications via apt-get:

  • j2sdk1.4
  • tomcat5
  • apache2
  • apache2-threaded-dev
  • build-essentials
  • a2enmod

Tomcat configuration

Two important environment variables for Tomcat are CATALINA_HOME and CATALINA_BASE. The first one is where the Tomcat files are actually installed (on Ubuntu Dapper Drake, using apt-get, this is /usr/share/tomcat5). The second one is where each running instance of Tomcat looks to find the configuration files and web applications. In the default installation, these variables are set to the same value. What we are going to do is create a directory for each of our webapps, and then start multiple instances of Tomcat with a different CATALINA_BASE for each one.

My suggested location (although I am open to feedback) is to create a new directory called /usr/share/tomcat5/instances that contains your applications. Looking at that containing directory, though, you see something like:

4 drwxr-xr-x   2 root root 4096 2006-08-15 08:02 bin
4 drwxr-xr-x   5 root root 4096 2006-03-19 16:27 common
0 lrwxrwxrwx   1 root root   21 2006-03-23 22:17 conf -> /var/lib/tomcat5/conf
4 drwxr-xr-x   2 root root 4096 2006-03-23 22:17 .debian
0 lrwxrwxrwx   1 root root   14 2006-03-23 22:17 doc -> ../doc/tomcat5
0 lrwxrwxrwx   1 root root   21 2006-03-23 22:17 logs -> /var/lib/tomcat5/logs
4 drwxr-xr-x   5 root root 4096 2006-03-23 22:17 server
0 lrwxrwxrwx   1 root root   23 2006-03-23 22:17 shared -> /var/lib/tomcat5/shared
0 lrwxrwxrwx   1 root root   21 2006-03-23 22:17 temp -> /var/lib/tomcat5/temp
0 lrwxrwxrwx   1 root root   24 2006-03-23 22:17 webapps -> /var/lib/tomcat5/webapps
0 lrwxrwxrwx   1 root root   21 2006-03-23 22:17 work -> /var/lib/tomcat5/work


You will notice that all the actual files are stored in /var/lib/tomcat5 with symbolic links across to them. To keep with this tradition, I used the following commands (all as root):

mkdir /var/lib/tomcat5/instances
ln -s /var/lib/tomcat5/instances /usr/share/tomcat5/instances
cd /usr/share/tomcat5/instances


So, now the base directories have been created, you need to do the initial setup for the Tomcat servers. Run the following commands for your webapp (where myapp is the name of your webapp):

mkdir -p myapp/conf myapp/logs myapp/webapps
cp ../conf/server.xml myapp/conf
cp ../conf/web.xml myapp/conf


Copy your application WAR file into the myapp/webapps directory, and we should be ready to go.

Starting your new instance

We can’t use the original /usr/share/tomcat5/bin/startup.sh to start each instance because it uses the default CATALINA_BASE, so what we do is create a new script file that can start and stop each instance, but pointing to a different CATALINA_BASE. Create a file called /usr/share/tomcat5/instances/myapp/myapp.sh that contains the following:

#!/bin/sh

RETVAL=$?
export JAVA_HOME=/usr/lib/j2se/1.4
export CATALINA_BASE="/usr/share/tomcat5/instances/myapp"
export CATALINA_HOME="/usr/share/tomcat5"
export CATALINA_PID=$CATALINA_BASE/logs/catalina.pid

case "$1" in
 start)
        if [ -f $CATALINA_HOME/bin/startup.sh ];
          then
            echo $"Starting Tomcat"
            exec $CATALINA_HOME/bin/startup.sh
        fi
        ;;
 stop)
        if [ -f $CATALINA_HOME/bin/shutdown.sh ];
          then
            echo $"Stopping Tomcat"
            exec $CATALINA_HOME/bin/shutdown.sh
        fi
        ;;
 *)
        echo $"Usage: $0 {start|stop}"
        exit 1
        ;;
esac
exit $RETVAL


Make sure the original Tomcat instance is stopped (by running sudo /etc/init.d/tomcat5 stop) and start your new instance by typing:

sudo chmod 755 ./myapp.sh
sudo ./myapp.sh start


Now test that Tomcat started up by pointing your browser to port 8180 of your machine with a valid myapp URL.

At this point, all we have really done is to make Tomcat start your application from a different directory. Useful, but not yet where we want to be. We realy want to be able to point the browser to port 80, instead of the non-typical port of 8180. So, we need to configure Apache to hand off to the new running instance using mod_jk.

mod_jk

mod_jk is the means by which Apache hands off incoming HTTP requests to the Tomcat instances. There are two flavours: mod_jk and mod_jk2. Despite what you would think, mod_jk is the more actively developed version and is actually much simpler to install and configure.

In the original version of Apache, you used to have to modify the httpd.conf file, however, with Apache2 things have changed a little. You can still edit /etc/apache2/httpd.conf if you like, but that isn’t the recommended way to configure Apache2. Instead, you will be creating configuration files in the following two directories:

  • /etc/apache2/mods-available
  • /etc/apache2/sites-available

Before you do that, however, you need to install mod_jk. Download the mod_jk source code, and run the following commands:

tar -xzvf jakarta-tomcat-connectors-1.2.14.1-src.tar.gz
cd jakarta-tomcat-connectors-1.2.14.1/jk/native
./configure --with-apxs=/usr/sbin/apxs2
make
sudo make install


The last command should install a file called mod_jk.so in /usr/lib/apache2/modules. You might want to just quickly check that it is there.

Now, you need to create a file called /etc/apache2/mods-available/jk.load that contains:

LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so

Next, create a file called /etc/apache2/mods-available/jk.conf that contains:

<IfModule mod_jk.c>
  JkWorkersFile       "/etc/apache2/workers.properties"
  JkLogFile           "/var/log/apache2/mod_jk.log"
  JkLogLevel          info
  JkLogStampFormat    "[%a %b %d %H:%M:%S %Y] "
  JkOptions           +ForwardKeySize +ForwardURICompat -ForwardDirectories
  JkRequestLogFormat  "%w %V %T"
</IfModule>

Now, from the command prompt, type the following commands to enable it and become effective. The a2enmod command enables a specific module by creating a symbolic link in /etc/apache2/mods-enabled that points to the equivalent file in /etc/apache2/mods-available directory.

sudo a2enmod jk
sudo /etc/init.d/apache2 force-reload

Nice work. Now you have enabled mod_jk. Now we have to configure a virtual host in Apache to point to our Tomcat instance. You do this by creating a file called /etc/apache2/sites-available/yourdomain.com and adding the following content:

<VirtualHost yourdomain:80>
        ServerAdmin admin@yourdomain.com
        ServerName  yourdomain.com
        ServerAlias www.yourdomain.com

        JkMount /* myapp
</VirtualHost>

This defines a virtual domain that has a Tomcat application called myapp. In fact, the myapp identifier is not actually the application name, but actually references an entry in the workers.properties file (see below). However, while not strictly necessary, if you keep this naming convention it makes it nice and easy to read the configurations when your mod_jk identifiers are the same as your webapp names. The JkMount /* myapp directive instructs Apache to send all urls to Tomcat (via mod_jk). You can, if you choose, a different pattern that more accurately reflects which requests you want Tomcat to handle (for example, JkMount /*.do myapp).

You need to make this new site available for use, so type the following command:

sudo a2ensite yourdomain.com
sudo /etc/init.d/apache2 force-reload

And lastly, we need to tell mod_jk what port Tomcat will be listening on by creating the configuration file that we referenced in /etc/apache2/mods-available/jk.conf. So, create a new file called /etc/apache2/workers.properties that contains:

worker.list=myapp

# Set properties for myapp
worker.myapp.type=ajp13
worker.myapp.host=localhost
worker.myapp.port=8009

The worker.list directive says which of the configurations is available for use. For now, only myapp is available because we have only got one application. This tutorial has Tomcat and Apache on the same machine, so we use localhost as the host. The port that mod_jk will send connections to is 8009, which is the default Tomcat AJP13 listening port. When we add second, and subsequent, applications we will use different port numbers.

Stop and restart Apache by running the following command:

/etc/init.d/apache2 restart

Now, point your browser to your machine, but on port 80 this time. If all has gone well, you should seamlessly get passed through Apache into Tomcat via AJP.

The last thing to do is make Tomcat only accept incoming connections via the AJP connector, instead of allowing connections directly to port 8180 (the HTTP connector). This can be done by editing the myapp/conf/server.xml to comment out the HTTP connector.

<!-- Connector className="org.apache.coyote.tomcat5.CoyoteConnector"
               port="8180" minProcessors="5" maxProcessors="75"
               enableLookups="true" acceptCount="10" debug="0"
               connectionTimeout="20000" useURIValidationHack="false" / -->

Adding second and subsequent webapps

Adding additional webapps is reasonably straightforward. One thing to decide before proceeding is what port numbers to use for your new webapp(s). The default server.xml will have the shutdown port being 8005 and the AJP connector port being 8009. Now, we already know that our first webapp (myapp, in this example) is using those ports, so we need to pick new port numbers. You can pick any port numbers you like, but the convention seems to be 8105/8109 for the second webapp, 8205/8209 for the third, and so on. The required steps are outline below:

  1. Run the following commands:

    mkdir -p app2/conf app2/logs app2/webapps
    cp ../conf/server.xml app2/conf
    cp ../conf/web.xml app2/conf
    

  2. Edit the app2/conf/server.xml, changing these items:
    • Change the port attribute of the <Server> tag from 8005 to 8105.
    • Change the port attribute of the AJP <Connector> tag from 8009 to 8109.
    • Optionally, comment out the HTTP <Connector> tag. If you don’t comment it out (and you didn’t comment it out in myapp/conf/server.xml) you will need to change the value from 8180 to 8181 (or some other port) so that the HTTP connectors of your two webapps aren’t listening on the same port.
  3. Edit the /etc/apache2/workers.properties to add new lines that look like:

    worker.list=myapp,app2
    
    # Set properties for myapp
    worker.myapp.type=ajp13
    worker.myapp.host=localhost
    worker.myapp.port=8009
    
    # Set properties for app2
    worker.app2.type=ajp13
    worker.app2.host=localhost
    worker.app2.port=8109
    

  4. Create a file called /etc/apache2/sites-available/anotherdomain.com and adding the following content:

    <VirtualHost anotherdomain:80>
            ServerAdmin admin@anotherdomain.com
            ServerName  anotherdomain.com
            ServerAlias www.anotherdomain.com
    
            JkMount /* app2
    </VirtualHost>
    

  5. Enable your new site by running the following commands:

    sudo a2ensite anotherdomain.com
    sudo /etc/init.d/apache force-reload
    

  6. Copy the myapp/myapp.sh script as app2/app2.sh directory, and modify the line with CATALINA_BASE to point to the app2 directory instead of the myapp directory.
  7. Copy your application WAR file into the app2/webapps directory
  8. Restart Apache by running /etc/init.d/apache2 restart
  9. Start your application by running app2.sh start

Starting automatically

Now, having installed your webapp successfully, you may want to get it to start automatically upon a system restart. The conventional way to do this is to run the following commands:

sudo ln -s /usr/share/tomcat5/instances/myapp/myapp.sh /etc/init.d/myapp.sh
sudo update-rc.d /etc/init.d/myapp.sh defaults 70


Repeat these commands for whichever Tomcat servers you want automatically restarted.

Feedback

If you spot any typos or mistakes, please let me know and I will correct ASAP. Thanks a lot.

11 Responses to “Configuring Tomcat5 and Apache2 to run with multiple instances”

  1. JD Evora Says:

    I was looking at your blog and noticed that with firefox, all the “shell captures” get cut and I don’t see anything wider than the normal text. e.g: The directory that I see is:

    4 drwxr-xr-x 2 root root 4096 2006-08-15 08
    4 drwxr-xr-x 5 root root 4096 2006-03-19 16
    0 lrwxrwxrwx 1 root root 21 2006-03-23 22
    4 drwxr-xr-x 2 root root 4096 2006-03-23 22
    0 lrwxrwxrwx 1 root root 14 2006-03-23 22
    0 lrwxrwxrwx 1 root root 21 2006-03-23 22
    ……

    Cheers and thanks for the description.
    JD

  2. edwardaux Says:

    Yes, unfortunately, I am struggling to stop the default wordpress theme from truncating some of the data. If you cut’n'paste, though, you can actually see everything. Anyway, for your reference, the files are:

    bin
    common
    conf -> /var/lib/tomcat5/conf
    .debian
    doc -> ../doc/tomcat5
    logs -> /var/lib/tomcat5/logs
    server
    shared -> /var/lib/tomcat5/shared
    temp -> /var/lib/tomcat5/temp
    webapps -> /var/lib/tomcat5/webapps
    work -> /var/lib/tomcat5/work


    edwardaux

  3. The Stone Edge » Blog Archive » Setup Apache with multiple Tomcat instances in SUSE 10.1 Says:

    [...] a script to control Tomcat instances.This script is mostly from this article: http://edwardaux.wordpress.com/2006/09/20/3/. I just add one more argument to make it more flexible. Download the attached script (tomcat.sh) to [...]

  4. Scott Ryan Says:

    WOW This is an awesome tutorial. I have been stuggling for weeks trying to get my apache and tomcat hooked together. After only 30 minutes and your notes in hand I had it up and running. I had a few typos but your directions were spot on. FYI If you are on ubuntu the mod_jk can be downloaded via the package manager and you can avoid building your own copy. This was awesome I wish more instructions on the web were this simple and actually worked.

    Thanks again

    Scott Ryan

  5. Lou Says:

    One word of warning:

    Be sure to disable selinux before trying this… if it’s in “enforcing” mode, you’re in for a lot of wasted hours debugging and tearing your hair out (like I did today).

  6. Andy Says:

    Thanks for this walkthrough. I ended up going a little different route, but my task was much easier thanks to you.

    as opposed to making a new script for starting/stopping each tomcat instance, I made the following changes to the existing /etc/init.d/tomcat5.5, that allows you to set the CATALINA_BASE from the command line when calling the script:

    — /etc/init.d/tomcat5.5 2006-11-22 15:51:29.000000000 -0600
    +++ tomcat5.5 2007-05-15 11:00:26.000000000 -0500
    @@ -55,6 +55,10 @@ if [ -f "$DEFAULT" ]; then
    . “$DEFAULT”
    fi

    +# overwrite CATALINA_BASE from command line parameter
    +[ ! -z "$2" ] && CATALINA_BASE=”$CATALINA_HOME/instances/$2″
    +echo “Using CATALINA_BASE: $CATALINA_BASE”
    +
    test -f $DAEMON || exit 0

    [ -z "$TOMCAT5_USER" ] && TOMCAT5_USER=tomcat55

  7. fropype Says:

    ford portland oregon

  8. running multilple instance of tomcat « Taydo Says:

    [...] http://edwardaux.wordpress.com/2006/09/20/3/ [...]

  9. Simon Says:

    Hi – great tutorial, thanks. One small problem I had was with one of the commands given to launch tomcat at startup:

    sudo update-rc.d /etc/init.d/myapp.sh defaults 70

    I got this error

    update-rc.d: /etc/init.d//etc/init.d/myapp.sh: file does not exist

    …seems it was automatically prepending ‘/etc/init.d/’.

    i changed the command to

    sudo update-rc.d myapp.sh defaults 70

    and it worked fine.

    thanks again!

  10. how do you pee outside Says:

    emm… 10x :)

  11. Azhar Ali Buttar Says:

    Hi,

    No doubt its a very good post but in very lengthly manner. I was trying to configure it using the above method but was very difficult for me to configure the basic setup. I got a very good post on itoperationz.com for multiple instances of apache tomcat6 at under given URL;

    http://www.itoperationz.com/2009/07/multiple-instances-of-apache-tomcat-6-on-debain5-lenny/

Leave a Reply