This blog post describes how to set up Tomcat to run multiple applications running as separate JVM processes, using the same Tomcat installation. This method utilizes the CATALINA_HOME
and CATALINA_BASE
environment variables used by Tomcat. I have verified this method against Tomcat versions 8.0.x
; other versions should work the same way.
A typical Tomcat installation
If we explode the Tomcat 8.0.23 tarball, we get the following directory structure:
$ tar apache-tomcat-8.0.23.tar.gz
$ ls apache-tomcat-8.0.23/
LICENSE RELEASE-NOTES bin lib temp work
NOTICE RUNNING.txt conf logs webapps
This distribution, by default runs applications in a single JVM. How does it do this?
Tomcat control scripts - startup.sh
, shutdown.sh
, catalina.sh
uses the environment variables CATALINA_HOME
and CATALINA_BASE
to locate binaries and configuration files.
From the documentaion inside catalina.sh
under apache-tomcat-8.0.23/bin/
we can see that:
# CATALINA_HOME May point at your Catalina "build" directory.
#
# CATALINA_BASE (Optional) Base directory for resolving dynamic portions
# of a Catalina installation. If not present, resolves to
# the same directory that CATALINA_HOME points to.
This allows us to separate the CATALINA_HOME
and CATALINA_BASE
directories. The Tomcat binaries and scripts need to be inside CATALINA_HOME
and our first application can deploy itself to CATALINA_BASE
.
Separating CATALINA_HOME and CATALINA_BASE
The app1
directory will have the following directories:
$ ls -a app1/
. .. bin conf logs temp webapps work
The bin
directory will have the setenv.sh
script used to set additional environment variables for the application.
The tomcat
directory will have the following directories:
$ ls tomcat/
LICENSE NOTICE RELEASE-NOTES RUNNING.txt bin lib
The bin
directory will have the Tomcat management scripts like startup.sh
, shutdown.sh
, catalina.sh
etc.
Now we can start app1
by pointing CATALINA_BASE
to app1
and CATALINA_HOME
to tomcat
.
$ export CATALINA_HOME=/Users/sdqali/src/sandbox/tomcat
$ export CATALINA_BASE=/Users/sdqali/src/sandbox/app1
$ $CATALINA_HOME/bin/startup.sh
$ $CATALINA_HOME/bin/startup.sh
Using CATALINA_BASE: /Users/sdqali/src/sandbox/app1
Using CATALINA_HOME: /Users/sdqali/src/sandbox/tomcat
Using CATALINA_TMPDIR: /Users/sdqali/src/sandbox/app1/temp
Using JRE_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home
Using CLASSPATH: /Users/sdqali/src/sandbox/tomcat/bin/bootstrap.jar:/Users/sdqali/src/sandbox/tomcat/bin/tomcat-juli.jar
Tomcat started.
$ curl -s -D - -o /dev/null http://127.0.0.1:8080
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 09 Jun 2015 07:37:43 GMT
Let’s try and deploy a second application app2
running on port 9090
.
$ export CATALINA_HOME=/Users/sdqali/src/sandbox/tomcat
$ export CATALINA_BASE=/Users/sdqali/src/sandbox/app2
$ $CATALINA_HOME/bin/startup.sh
Using CATALINA_BASE: /Users/sdqali/src/sandbox/app2
Using CATALINA_HOME: /Users/sdqali/src/sandbox/tomcat
Using CATALINA_TMPDIR: /Users/sdqali/src/sandbox/app2/temp
Using JRE_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home
Using CLASSPATH: /Users/sdqali/src/sandbox/tomcat/bin/bootstrap.jar:/Users/sdqali/src/sandbox/tomcat/bin/tomcat-juli.jar
Tomcat started.
$ curl -s -D - -o /dev/null http://127.0.0.1:9090
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 09 Jun 2015 07:41:02 GMT
Tying it all together
At this point, it is useful to create management scripts that abstract away the environment variables and allows for starting up and shutting down applications individually. The start.sh
script will be as follows.
#!/usr/bin/env sh
# start.sh
# Script to start a Tomcat application
show_usage() {
echo "Usage: ./start.sh <app-name>";
exit 1;
}
declare app_name=$1;
[[ -z $app_name ]] && show_usage;
declare INSTALL_BASE=/Users/sdqali/src/sandbox
export CATALINA_HOME=$INSTALL_BASE/tomcat
export CATALINA_BASE=$INSTALL_BASE/$app_name
$CATALINA_HOME/bin/startup.sh
Similarly, the stop.sh
script will be:
#!/usr/bin/env sh
# stop.sh
# Script to stop a Tomcat application
show_usage() {
echo "Usage: ./stop.sh <app-name>";
exit 1;
}
declare app_name=$1;
[[ -z $app_name ]] && show_usage;
declare INSTALL_BASE=/Users/sdqali/src/sandbox
export CATALINA_HOME=$INSTALL_BASE/tomcat
export CATALINA_BASE=$INSTALL_BASE/$app_name
$CATALINA_HOME/bin/shutdown.sh
We can manage individual applications using these scripts:
$ ./management/start.sh app2
Using CATALINA_BASE: /Users/sdqali/src/sandbox/app2
Using CATALINA_HOME: /Users/sdqali/src/sandbox/tomcat
Using CATALINA_TMPDIR: /Users/sdqali/src/sandbox/app2/temp
Using JRE_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home
Using CLASSPATH: /Users/sdqali/src/sandbox/tomcat/bin/bootstrap.jar:/Users/sdqali/src/sandbox/tomcat/bin/tomcat-juli.jar
Tomcat started.
$ nc -z 127.0.0.1 9090
Connection to 127.0.0.1 port 9090 [tcp/websm] succeeded!
$ curl -s -D - -o /dev/null http://127.0.0.1:9090
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 09 Jun 2015 08:16:05 GMT
$ ./management/stop.sh app2
Using CATALINA_BASE: /Users/sdqali/src/sandbox/app2
Using CATALINA_HOME: /Users/sdqali/src/sandbox/tomcat
Using CATALINA_TMPDIR: /Users/sdqali/src/sandbox/app2/temp
Using JRE_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home
Using CLASSPATH: /Users/sdqali/src/sandbox/tomcat/bin/bootstrap.jar:/Users/sdqali/src/sandbox/tomcat/bin/tomcat-juli.jar
$ nc -z 127.0.0.1 9090
$ curl -v http://127.0.0.1:9090
* Rebuilt URL to: http://127.0.0.1:9090/
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* connect to 127.0.0.1 port 9090 failed: Connection refused