Installing Tomcat 4.1.18
This is a log of my install of Tomcat 4.1.18 binary under Red
Hat Linux 8.0
Jan Labanowski, Mar. 8, 2003
1. The problem with Red Hat Linux is that when you ask it to install
Everything, it actually does not install everything. You will be
missing a lot of useful stuff. If something does not work, just
install DEVELOPMENT version of it.
2. First you need Java SDK. I installed the latest greatest 1.4.1.
Point your browser to http://java.sun.com/ and click on J2SE 1.4.1
(Standard Edition) download. While you can download Java install
files to /tmp you may want to put it in a more permanent directory
in case you want to reinstall Java later. Click on J2SE downloads.
Click on J2SE 1.4.1. You will see a table. Do not take anything from
JRE column since JRE is a part of SDK. I retrieved
"Linux self-extracting file" since it can be unpacked in any directory,
while RPM is easier, but goes to a predefined directory.
- Accept the license
- Click on Download j2sdk-1_4_1_02-linux-i586.bin .
Filesize = 42,250,657 bytes.
I saved it in the /root/j2sdk-1_4_1_02-linux-i586.bin
Then I ran:
cd /root
sh j2sdk-1_4_1_02-linux-i586.bin
Answered Yes to license terms
This created a directory:
/root/j2sdk1.4.1_02
I moved this directory to /usr/local:
cd /root
mv j2sdk1.4.1_02 /usr/local
cd /usr/local
ln -s j2sdk1.4.1_02 j2sdk1.4.1
I appended the following to the files in home directories of accounts
which will use this Java SDK:
Appended to .bashrc
JAVA_HOME=/usr/local/j2sdk1.4.1
PATH=${JAVA_HOME}/bin:${PATH}
MANPATH=${JAVA_HOME}/man:${MANPATH}
export JAVA_HOME PATH MANPATH
You you should also run these commands in your current terminal window
to set necessary environment variables. Also, add lines below to .chsrc
of accounts which run csh or tcsh shell:
setenv JAVA_HOME /usr/local/j2sdk1.4.1
setenv PATH ${PATH}:/usr/local/j2sdk1.4.1/bin
setenv MANPATH /usr/local/j2sdk1.4.1/man:${MANPATH}
Default distribution on Java SDK comes with weak encryption (some
governments do not like you to install strong encryption and they want
to read your stuff -- they say it is for your protection, since
they want to read files of bad guys -- the problem is that
bad guys are using strong encryption and do not give a damn about what
government wants. Moreover, government knows it very well).
To upgrade your encryption, you need to download another file from
Sun. Go to: http://java.sun.com/j2se/1.4.1/download.html and get
to the bottom of the page and get Java Cryptography Extension (JCE)
Unlimited Strength Jurisdiction Policy Files:
You will get a file of 9715 Bytes: jce_policy-1_4_1.zip
Unzip the file anywhere: (e.g., you can use a command:
/usr/local/j2sdk1.4.1/bin/jar xvf jce_policy-1_4_1.zip
and use the Java jar utility you have just installed. You can also use
the regular unzip program which comes with Linux.
unzip jce_policy-1_4_1.zip
In any case, the jce directory will be created with the following
files:
README.txt This file
COPYRIGHT.html Copyright information
local_policy.jar Unlimited strength local policy file
US_export_policy.jar Unlimited strength US export policy file
Copy these files to lib/security directory of your Java Runtime
Environment. In short, I did (Yes, I did set up the JAVA_HOME
variable as described above):
cd /wherever/it/is/.../jce
mkdir ${JAVA_HOME}/jre/lib/security/limited-strength
cp -p ${JAVA_HOME}/jre/lib/security/*.jar \
${JAVA_HOME}/jre/lib/security/limited-strength
cp * ${JAVA_HOME}/jre/lib/security
Now, I also downloaded docs for Java. With my browser went to:
http://java.sun.com/j2se/1.4.1/download.html
Toward the bottom, under the heading: J2SE v 1.4.1 Documentation
there is the [Download] entry under JRE column (unfortunately, there is
no easy download for documents for J2SDK). Click, accept the license,
and download the zip file with docs: Download j2sdk-1_4_1-doc.zip
(32,765,641 bytes).
Then, I unpacked the zipped docs in JAVA_HOME:
cd $JAVA_HOME
unzip /full/path/j2sdk-1_4_1-doc.zip
This created a docs directory under JAVA_HOME. Later, I will link
this directory to Tomcat webapps later. To see if my Java install worked,
I created a simple application which prints the Java version and
vendor. Get it HERE or cut&paste from below:
--------------- Cut and put into file: HelloWorld.java ---------------
class HelloWorld {
public static void main(String[] args) {
String systemProperties [] = {
"java.vendor",
"java.vendor.url",
"java.version",
"java.class.version",
"os.name",
"os.arch",
"os.version"
};
for (int i=0; i < systemProperties.length; i++) {
try {
String key = systemProperties[i];
String value = System.getProperty(key);
System.out.println("\nProperty: " + key +
"\nValue: " + value);
} catch ( Exception e ) {
System.err.println("Exception " + e);
}
}
}
}
---------------- end of file: HelloWorld.java ---------------
Then I compiled the source code as:
javac javac HelloWorld.java
and I ran it:
java HelloWorld
It happily produced:
Property: java.vendor
Value: Sun Microsystems Inc.
Property: java.vendor.url
Value: http://java.sun.com/
Property: java.version
Value: 1.4.1_02
Property: java.class.version
Value: 48.0
Property: os.name
Value: Linux
Property: os.arch
Value: i386
Property: os.version
Value: 2.4.18-24.8.0
(I told you, I did the upgrades of RH8.0, didn't I?).
3. Before you do anything, explore Jakarta site:
http://jakarta.apache.org/ and find out what is
the latest STABLE release of Tomcat. In this case it is 4.1.18,
but in a few weeks, it will not be the latest.
Also READ the documents and HOWTOs.
It is convenient to run Tomcat as a user different than root.
If you need to run Tomcat on the regular "well known ports", i.e,.
80 (for HTTP), and 443 (for HTTPS) you have to run Tomcat as root.
Server ports with numbers less than 1025 can only be opened by
a superuser. Native code can do the trick by opening lower ports as
root user and changing itself to another non-root user (this operation
is called setuid). Code written in Pure Java cannot perform the setuid
operation and therefore once started as root, will run as root.
However, running as root, is DANGEROUS!!!. It is ESPECIALLY dangerous
to run Web server as root, since you have no control over data which
are fed to your server. While Tomcat is very safe, your own code in Java
might not be. Small mistakes (even gurus make them), and your Java Server
Page or servlet may be used to attack your computer (or other computers
using your computer as a lunch pad). It is therefore a VERY GOOD
PRACTICE to run Tomcat as user other than root.
There are many ways to serve standard Web ports (80, 443) by Tomcat,
yet run Tomcat as a non-root user. You need to put a piece of native
code (written usually in C) between your Tomcat running as non-root and
the real world out there. This topic is too long to cover here, but
essentially, you have some options:
a) Use Apache (or some other Web server), running as native code,
as a front, and connect Tomcat to the Web server via a connector
module (or run Tomcat inside a native web server process as a thread)
Search web for words: Apache connector module tomcat
b) Use a firewall software capable of translating port numbers.
Assuming that your HTTP port for Tomcat is 8080, and HTTPS
port is 8443, you can run Tomcat as non-root, and the firewall
will rewrite the destination port number in the incoming TCP
packet (request) from 80 to 8080, (or 443 to 8443), and do the
reverse for the source port number in the outgoing packet (response).
Redhat comes with iptables firewall. Write a set of rules to remap
ports (check the following URLs and search http://google.com:
http://www.wrox.com/books/sample-chapters/SampleChapter_1861008309.pdf,
http://www.projectforge.org/Administration.pdf,
http://www.netikus.net/documents/Linux-Cocoon.pdf).
c) Use some specialized piece of native code to do this. Check
perl archives (CPAN) for a piece of code called tunnel.pl
(check for example:
http://www.ks.uiuc.edu/Research/biocore/localServer/install/sample/webTunnel.
)
4. Create a new user and group to run tomcat on your machine.
I use the user webrun or tomcat or tomcat41180 or whatever.
It is convenient to have a specific user associated with the given
version of tomcat, so when you need to kill or restart Tomcat you
can easily see what is running and what is not. First, check if
the group and user (and the corresponding uid and gid) exist by
grepping or looking at /etc/passwd and /etc/group. Then create
a new group and a new user:
groupadd -g 41180 tomcat41180
useradd -c 'Tomcat 4.1.18' -d /usr/local/tomcat-4.1.18 -g tomcat41180 \
-m -s /bin/bash -u 41180 tomcat41180
passwd tomcat41180
This will create group for and user id for tomcat41180,
create home directory, and change the password to what you want it to be.
The home directory will be /usr/local/tomcat-4.1.18
Then log out as root and log in as tomcat41180.
5. Once you are logged in user tomcat41180 add this to .bashrc file in the
HOME directory:
JAVA_HOME=/usr/local/j2sdk1.4.1
PATH=${JAVA_HOME}/bin:${PATH}
MANPATH=${JAVA_HOME}/man:${MANPATH}
export JAVA_HOME PATH MANPATH
and log out and log in again as tomcat41180.
I retrieved BINARY Tomcat distribution from Jakarta
Apache site: http://jakarta.apache.org/ being in HOME
directory of tomcat41180. Note that there are two distributions
of Tomcat: the one with Xerces XML parser (regular distribution)
and the Lightweight distribution which does not bundle the Services parser.
The "regular" distribution is will not run out of the box with the
J2SE 1.4.1 JDK since JDK has its own XML parser (JAXP). You would have
to reconfigure several things to make it run. The solution is to use
"Lightweight" binary distribution which does not have XML parser bundled
and will run out of the box with the J2SE 1.4.1 JDK. So why should anyone
ever look at "regular" distribution?. It is a separate topic, but:
a) People often use other JDKs than Sun's (Why? Since they can
be redistributed with your application, while Sun's cannot).
b) Xerces has a lot of functionality which JAXP does not have (yet...).
c) Java 1.4.X is not yet ported to all computer architectures and
systems, and for these systems you need to use the older versions
of Java which do not yet bundle the JAXP.
I used wget to retrieve the binary distribution (but you can
just use regular browser). Note, I used the gzipped tar distribution.
There is also RPMs, but if you want to have a freedom where you place
your Tomcat files, use the tgz. I logged in as tomcat41180 and did:
wget http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.1.18/bin/jakarta-tomcat-4.1.18-LE-jdk14.tar.gz
tar zxvf jakarta-tomcat-4.1.18-LE-jdk14.tar.gz
cd jakarta-tomcat-4.1.18-LE-jdk14
mv * .. # copy files one dir up
cd .. # go one up
rmdir jakarta-tomcat-4.1.18-LE-jdk14 # remove it - it is empty
i.e., I moved all components to the HOME directory of tomcat41180.
In the .bashrc file I added lines at the end :
TOMCAT_HOME=/usr/local/tomcat-4.1.18
CATALINA_HOME=/usr/local/tomcat-4.1.18
PATH=${TOMCAT_HOME}/bin:${PATH}
export TOMCAT_HOME PATH CATALINA_HOME
and logged out and logged in again as tomcat41180
Now, making tomcat RUN. You definitely need to read files:
${TOMCAT_HOME}/RUNNING.txt ${TOMCAT_HOME}/README.txt which come
with the distribution. I started from making sure that my port
assignments do not collide with other servers which I run on the machine.
I edited the ${TOMCAT_HOME}/conf/server.xml file and made all ports
original starting from 80xx to start from 418xx. In my case these
ports did not collide with anything else running on the machine, which
I checked by doing:
netstat -n | grep 412
I made following changes in ${TOMCAT_HOME}/conf/server.xml:
8005 --> 41805
8008 --> 41808
8009 --> 41809
8080 --> 41880
8082 --> 41882
8083 --> 41883
8443 --> 41843
Note that most statements using these ports are commented out.
But I changed just in case, so it is consistent in case I later
need to uncomment some connectors. The server.xml file patched
as described above is available HERE
6. Testing tomcat. Before starting Tomcat, you need to set the
JAVA_HOME environmental variable (read $TOMCAT_HOME/bin/catalina.sh
script for more information). In my case the JAVA_HOME and TOMCAT_HOME
should have been already set in the .bashrc for the tomcat41180 user.
To start the Tomcat server, I did:
cd ${TOMCAT_HOME}/bin
./startup.sh
Then, when I pointed my browser at:
http://my.machine.com:41880
Note, there will be a slight delay when serving first page after
startup, since Tomcat needs to initialize a lot of stuff (e.g.,
random number generator seed) and compile JSP pages (check the
${TOMCAT_HOME}/work subdirectories for compiled/translated JSP
pages and servlets). In the URL above put of course, the actual
name or IP address of your machine. To use it on a local host,
just use the URL: http://127.0.0.1:41880
In my case, I am behind the firewall which only lets through the
authorized ports. Port 41880 obviously is not one of them.
I had to add a rule to my IPTABLES to let the
packets through. Check your firewall if things should work and
do not (e.g., if everything works fine with http://localhost41880
but you cannot access the server from another computer).
After I played with examples and pages (whose sources are in the
${TOMCAT_HOME}/webapps directory) I stopped Tomcat
cd ${TOMCAT_HOME}/bin
./shutdown.sh
7. There may be a situation when you want all developers to have
a password to the tomcat41180 (or whatever) account which owns
all files of Tomcat. But, you may also want to have the situation
when people own/can modify subdirectories under ${TOMCAT_HOME}/webapps,
i.e., the individual web applications. This is not really 100% secure
solution if you wanted to protect the integrity of the Tomcat
installation, since people can always write a Java code which can
do anything the user "tomcat41180" can do (e.g., delete/modify files
which are owned/writable by user which runs Tomcat). If security
is the issue, you have no recourse, but to create separate Tomcat
installations each owned by the respective developer. However, in
a regular development environment, it is not an issue, and it is
rather a case when we need to sensibly protect people against mistakes
(not malice) made by others.
If you create webapps owned by individual developers so they do not
get into each other way, there is still the problem that Tomcat needs
to be restarted, or killed sometimes. Some profoundly messed up Java
code can affect Tomcat performance or even hang it (imagine something
which runs tight infinite loop, for example). Moreover, sometimes,
especially when you use compile time includes in JSP, the easiest way
to make Tomcat aware of the changes is to restart Tomcat, and even
delete temporary files in the directory.
These actions can only be done by the user who has privileges,
i.e., root or the "tomcat41180" who owns Tomcat files.
To allow other users to perform these actions, I created a few
scripts and C-wrappers. In UNIX, when you set up a SETUID bit on
an executable file, it will execute as user which owns it. To ensure
that both the real and effective user id is changed, I use few more
lines in the C wrapper. While in the beginning of time, UNIXES allowed the
shell scripts to have SETUID bit set and active, this option is
disabled by default on most installation to enhance security.
The way around is to write a C program (a C wrapper) which executes
the script by calling a system library function. The full path
to the script should be used, and script should not be writable by
anyone but root of the owner of the setuid C wrapper program.
C wrapers work, since SETUID but works by default on binary executables.
I created shell scripts and corresponding wrappers which
are given below as links. If you use some other account and other
paths/file locations, you need to modify these scripts.
start_tomcat41180.sh -- a shell script which sets some
environment variables. It then calls the startup.sh script, which
comes with Tomcat. It is assumed that the script resides in the
/usr/local/tomcat-4.1.18/bin directory and is owned and
writable only by user "tomcat41180" and that user and group
id of tomcat41180 is 41180. Remember to change mode of this
script once you put it where it belongs:
cd /usr/local/tomcat-4.1.18/bin
chmod 755 start_tomcat41180.sh
start_tomcat41180.c -- a C wrapper for the start_tomcat.sh script.
It should be compiled, and installed as below when you are logged
in as root:
gcc -o start_tomcat41180 start_tomcat41180.c
chown root:root start_tomcat41180
chmod 711 start_tomcat41180
chmod ug+s start_tomcat41180
mv start_tomcat41180 /usr/local/bin
Before you start tomcat, make sure that it does not already run
(run script: ps-tomcat41880 described below), or just run
stop_tomcat41180 program as described below. Once you are sure
that tomcat is not running, type:
start_tomcat41180
to start Tomcat.
stop_tomcat41180.sh -- a shell script which sets some
environment variables. It then calls the shutdown.sh script, which
comes with Tomcat. It is assumed that the script resides in the
/usr/local/tomcat-4.1.18/bin directory and is owned and
writable only by user "tomcat41180" and that user and group
id of tomcat41180 is 41180. Remember to change mode of this
script once you put it where it belongs:
cd /usr/local/tomcat-4.1.18/bin
chmod 755 stop_tomcat41180.sh
stop_tomcat41180.c -- a C wrapper for the stop_tomcat.sh script.
It should be compiled, and installed as below, when you are logged
in as root:
gcc -o stop_tomcat41180 stop_tomcat41180.c
chown root:root stop_tomcat41180
chmod 711 stop_tomcat41180
chmod ug+s stop_tomcat41180
mv stop_tomcat41180 /usr/local/bin
To stop Tomcat server, type:
stop_tomcat41180
You may ask why I did: chown root:root stop_tomcat41180 while
chown tomcat41180:tomcat41180 stop_tomcat41180 would
also work? I strongly believe that files in standard public
directories like /bin, /usr/bin, /etc, etc... should be owned by
root, so only root can change them. What if some jerk replaced
the stop_tomcat41180 with a script "rm -r *" and removed the setuid
bits? It is in principle possible from within a servlet or JSP page
run by Tomcat. The unsuspecting soul would have all its files
removed from below the current directory. If files are owned by
root the only thing which can be done is that the stop_tomcat41180.sh
script (or shutdown.sh, or whatever it calls) can be messed up,
but they only execute as user tomcat41180 and can only mess up
files writable by this user. In the production (as opposed to
development environment described here) all files/directories
under Tomcat should be owned by root with exception of the ones
which Tomcat changes itself, i.e., subdirectories work,
temp, and logs.
ps-tomcat41180.sh -- a shell script which lists process
ids (in 2nd column) of all processes which run as user tomcat41180.
Put it in /usr/local/bin and change its mode to 755. It is a simple
shell script which has only one line:
ps -u tomcat41180 -fww
It is useful to check if your (or whoever) code creates some
stray processes from within Tomcat. Such things can be created
(e.g., by the Runtime facility of Java in your servlets or JSPs).
They will run with the id of the user which runs Tomcat, i.e.,
tomcat41180. Stopping Tomcat may or may not stop all these processes.
You may need to kill some of them manually. If something does not work
right, and you have problems when restarting Tomcat, check what still
runs after you Tomcat with stop_tomcat41180 command (just type:
ps-tomcat41180.sh
and see what it lists).
kill_tomcat41180.c -- a C setuid program which kills processes
owned by tomcat41180. If after stopping Tomcat with the stop_tomcat
command the ps-tomcat41180.sh script still shows some processes,
you may need to kill them. Be careful though, it may be the
administrator logged in as tomcat41180, or some other legitimate
process. Look carefully at the output of the ps-tomcat41180.sh script.
It should be compiled, and installed as below. You need to be
a root to run this:
gcc -o kill_tomcat41180 kill_tomcat41180.c
chown root:root kill_tomcat41180
chmod 711 kill_tomcat41180
chmod ug+s kill_tomcat41180
mv kill_tomcat41180 /usr/local/bin
The program takes one or more process ids (numbers from the
second column of the ps-tomcat41180.sh output).
Since it is setuid tomcat41180 it should be relatively safe
and should not kill other processes but only the ones owned by
tomcat41180. For example if you want to kill process 23455 23458
just type:
kill_tomcat41180 23455 23458
rm_work_tomcat41180.c -- a C setuid program which removes all files under the
/usr/local/tomcat-4.1.18/work directory. The files there
are JSP pages converted to servlets, and the Java classes crated
from them. If they are missing, they will be recreated by Tomcat.
Please use this script only when Tomcat is not running, since
otherwise you may confuse Tomcat that class is there while it was
just deleted. Why you would ever use this thing? Sometimes when
we include files into servlets/JSPs and we change these include
files, the change is not propagated to the compiled classes.
Tomcat only checks the Java source code and if did not change,
it may assume that no recompilation is necessary. In such case
cleaning work directory may help (it will not help though for
classes which you compiled yourself -- these you need to recompile
yourself). You deal with it as with all others, i.e.:
gcc -o rm_work_tomcat41180 rm_work_tomcat41180.c
chown root:root rm_work_tomcat41180
chmod 711 rm_work_tomcat41180
chmod ug+s rm_work_tomcat41180
mv rm_work_tomcat41180 /usr/local/bin
You clean work directory by just typing:
rm_work_tomcat41180
8. You may want to start tomcat at boot up of your machine.
Assuming that start_tomcat41180 and stop_tomcat41180 are in the
/usr/local/bin directory, you can place the following very
simple script tomcat41180
in the /etc/rc.d/init.d directory:
------------- cut here and put into /etc/rc.d/init.d/tomcat41180 -------
#!/bin/bash
#
# Startup script for the Tomcat Web Server
#
# chkconfig: 345 84 16
# description: Tomcat is a World Wide Web server. It is used to serve \
# HTML, JSP, and servlets, and CGI if needed.
# processname: java
# Source function library.
. /etc/rc.d/init.d/functions
if [ -f /etc/sysconfig/tomcat41180 ]; then
. /etc/sysconfig/tomcat41180
fi
case "$1" in
start)
/usr/local/bin/start_tomcat41180
;;
stop)
/usr/local/bin/stop_tomcat41180
;;
*)
echo $"Usage: tomcat41180 {start|stop}"
exit 1
esac
exit 0
------------- cut here: end of file /etc/rc.d/init.d/tomcat41180 -------
then do (obviously as root):
cd /etc/rc.d/init.d
chmod 755 tomcat41180
chkconfig --add tomcat41180
chkconfig --list tomcat41180
Tomcat should now start automatically at boot.
=================
If you got this far, send corrections/typos/curses/thankyous to jkl@ccl.net.