Last year we had Tomcat working on one of our machines with multiple virtual hosts. It was good, then this year we upgraded to a new version of linux, bringing everything else up with it as well and suddenly things did not work. The new specs included:
|
|
|
|
|
So it was a fairly significant upgrade and not surprising that things broke. This is the story of how I got things working.
APACHE
Apache is the webserver of choice. I prefer to compile from source. First step is you'll need to get the source. Grab the md5sum file while you're there as well.
|
# wget http://apache.mirror.pacific.net.au/httpd/httpd-2.0.49.tar.gz # wget http://www.apache.org/dist/httpd/httpd-2.0.49.tar.gz.md5 |
Check the md5sum of the downloaded file against what it is suppose to be and make sure they match. Assuming they do, you'll want to decompress the file, then compile it. Incidently, I put all my source files into /usr/local/src and all of the programs go into /usr/local with symbolic links pointing from the major program to the actual name. ie) If I install Program_Version_1.2.3 that will be installed in /usr/local/program_1.2.3 but then I'll create a symbolic link /usr/local/program back to that path.
Before I get started compiling, I create an Apache user and group. This is the userid that Apache will run on. (I usually call it "apache". I am nothing if not original). You'll need to edit your password, group and maybe your shadow file. Or you can use the adduser scripts to do it nicely for you.
|
# tar -xvf httpd-2.0.49.tar.gz |tar -xvf - # cd httpd-2.0.49 # ./configure --prefix=/usr/local/httpd-2.0.49 --enable-suexec --with-suexec-bin=/usr/sbin/suexec --with-suexec-docroot=/usr/local/httpd/htdocs --with-suexec-logfile --with-suexec-safepath --enable-module=so --enable-ssl --with-ssl=/usr/include/openssl CFLAGS="-I/usr/kerberos/include" --with-suexec-userdir=WWW --with-suexec-caller=apache --with-suexec-uidmin=101 --with-suexec-gidmin=101 --enable-module=mod_jk --enable-deflate --enable-maintainer-mode --enable-module=mod_dav --enable-module=mod_dav_fs --enable-dav --enable-dav-fs --enable-module=mod_rewrite --enable-rewrite # make # make install |
The configure line of Apache is worth a mention. It says to install Apache in /usr/local/httpd-2.0.49; compile in the suexec options (which we use); enable webdav; enable mod_rewrite and the maintainer mode allows for debugging. (Good in this particular case).
Assuming everything worked in the lines above, you'll now have apache installed in /usr/local/httpd-2.0.49. The next step I perform is a bundle of symbolic links. (Link /use/local/httpd to /usr/local/httpd-2.0.49; link /etc/httpd to /usr/local/httpd/conf for example) exactly what depends on your personal preference and the installation.
Edit /usr/local/httpd/conf/httpd.conf (or /etc/httpd/httpd.conf). I'm not going to go into details about that. It is relatively straightforward and the configuration file is very well documented.
Now you're ready to start Apache. Run the apachectl command
| # /usr/local/httpd/bin/apachectl start |
and point your browser to http://hostname and you should see the Apache welcome page. If not, look in the error logs and see what the problem is.
TOMCAT
Tomcat is "a servlet container that is used in the official Reference Implementation for the Java Servlet and JavaServer Pages technologies" (Tomcat Home Page). Essentially it allows you to use Java via a web interface.
Installing it is actually quite easy.
Get the source from http://apache.ausgamers.com/jakarta/tomcat-5/v5.0.25/bin/jakarta-tomcat-5.0.25.tar.gz, uncompress and copy to /usr/local and create a symbolic link. You'll also need to create a user to run the tomcat process under as well. I use the user/group "tomcat" :
|
# wget http://apache.ausgamers.com/jakarta/tomcat-5/v5.0.25/bin/jakarta-tomcat-5.0.25.tar.gz # gzip -dc jakarta-tomcat-5.0.25.tar.gz |tar -xvf - # cp -a jakarta-tomcat-5.0.25 /usr/local/ # cd /usr/local/ # chown -R tomcat:tomcat jakarta-tomcat-5.0.25 # ln -s jakarta-tomcat-5.0.25 tomcat |
Now you've got tomcat installed. Before you start it, you'll need to set an environmental variable JAVA_HOME. All the documentation says to set this in the shell startup scripts, however, I have more luck setting it directly in the Tomcat startup script. That is called catalina.sh and is located at /usr/local/tomcat/bin/catalina.sh. Just add the line export JAVA_HOME="/usr/java/jdk" to that file. That is assuming that your java directory is located in /usr/java/jdk. While you are there, at about line 70, under the block which gets the environmental variables add serverRoot=/etc/httpd and export serverRoot. This gets used later.
|
# Get standard environment variables PRGDIR=`dirname "$PRG"` CATALINA_HOME=`cd "$PRGDIR/.." ; pwd` if [ -r "$CATALINA_HOME"/bin/setenv.sh ]; then . "$CATALINA_HOME"/bin/setenv.sh fi # Added these lines serverRoot=/etc/httpd export serverRoot |
Once you've done that, start tomcat:
| # /usr/local/tomcat/bin/catalina.sh start |
and point your browser to http://hostname:8080 and you should see the tomcat welcome page. If not, then you've got problems. Find the examples on the left hand side of the page and double check that they work as well.
MOD_JK2
Mod_jk2 is a java connector. Essentially it acts as a translator, allowing Apache and Tomcat to talk to each other. Unfortunately it is a pain to set up.
Essentially its like anything else: download, compile and install. However, under Red Hat the configure script leaves out some libraries, so you need to manually edit one of the Makefiles to include them. First you need to get the source and prepare it:
|
# wget http://apache.ausgamers.com/jakarta/tomcat-connectors/jk2/source/jakarta-tomcat-connectors-jk2-2.0.4-src.tar.gz # gzip -dc jakarta-tomcat-connectors-jk2-2.0.4-src.tar.gz | tar -xvf - # cd jakarta-tomcat-connectors-jk2-2.0.4-src/jk/native2 # ./configure --with-apxs2=/usr/local/httpd/bin/apxs \ --with-apr-lib=/usr/lib \ --with-tomcat-41=/usr/local/tomcat \ --with-java-home=/usr/java/jdk \ --with-jni |
Now you need to find the file source_directory/jk/native2/server/apache2/Makefile inside that file you need to add some libraries.
|
Find the block --> ifdef APR_LIBDIR_LA JK_LDFLAGS=-L${APACHE2_LIBDIR} -lcrypt else JK_LDFLAGS=-lcrypt ${APR_LIBS} endif And change it to this: ifdef APR_LIBDIR_LA JK_LDFLAGS=-L${APACHE2_LIBDIR} -lcrypt else JK_LDFLAGS=-lcrypt ${APR_LIBS} JK_LDFLAGS=-lcrypt ${APR_LIBS} -L/usr/local/httpd-2.0.49/lib -laprutil-0 -lgdbm -ldb-4.0 -lexpat endif |
Note the extra LDFLAGS --> JK_LDFLAGS=-lcrypt ${APR_LIBS} -L/usr/local/httpd-2.0.49/lib -laprutil-0 -lgdbm -ldb-4.0 -lexpat
Finding out which flags can be a bit of a challenge. Exactly which flags will depends on your own installation.
The simple answer is to run apu-config, however there may be different versions. I discovered I had two versions installed. One in my path in /usr/bin/apu-config and another in /usr/local/httpd/bin/apu-config. You'll want to run the one which Apache uses, which was the one inside the httpd directory in my situation.
/usr/local/httpd/bin/apu-config --link-ld --libs returned a value of:
-L/usr/local/httpd/bin -laprutil-0 -lgdbm -ldb-4.2 -lexpat
These are the libraries which were compilied into apu-utils. If you don't specify these, you will get library errors when you try to start tomcat, resulting in the apr not loading.
In my case, it asked for the db4.2 library. I tried that, but when I compiled, it could not be found, so I did some searching and tried -ldb4.0 instead. That worked. I am guessing I forgot to add the path for db-4.2 to my /etc/ld.so.conf file.
Once you have edited that line, run a make command. Assuming that works you need to then run apxs and then you can copy the created modules from the tomcat source directory into the Apache module directory.
|
# cd ../build/jk2/apache2 # /usr/local/httpd/bin/apxs -n jk2 -i mod_jk2.so # cp libjkjni.so /usr/local/httpd/modules/jkjni.so # cp mod_jk2.so /usr/local/httpd/modules/ |
CONFIGURATION
Once everything is in place, there are four files that need to be modified:
# Sample mod_jk2.conf 08-Feb-2004, located at: # http://www.gknw.com/development/apache/docs/win32/mod_jk2/mod_jk2x.conf # # Load the mod_jk2 module # LoadModule jk2_module modules/mod_jk2.so |
The key thing to see here is the setting up of the worker. Make a note of the port, 8009 on localhost is standard, but you can move it if you wish. Also notice the URI setups.
/etc/httpd/workers2.properties
# workers2.properties # Shared memory handling. Needs to be set. [shm] info=Scoreboard. Required for reconfiguration and status with multiprocess servers file=/usr/local/tomcat/logs/jk2.shm size=1048576 debug=0 disabled=0 #UNIX domain socket [channel.un:/usr/local/tomcat/work/jk2.socket] tomcatId=localhost:8009 debug=0 # define the worker [ajp13:/usr/local/tomcat/work/jk2.socket] channel=channel.un:/usr/local/tomcat/work/jk2.socket # Not currently using sockets, using channels instead #[ajp13:localhost:8009] #channel=channel.socket:localhost:8009 # Announce a "status" worker pstatus:status] info=Status worker. Displays runtime information. [uri:/jkstatus/*] group=status:status # Uri mapping [uri:/examples/*] ### The default website [uri:projects.csse.uwa.edu.au/*.jsp] worker=ajp13:localhost:8009 ### Perth agentcity site [uri:perth-agentcity.csse.uwa.edu.au/*.jsp] worker=ajp13:localhost:8009 |
Notice here the channel definition. This tells tomcat where to go. We're using channels, not sockets. The other thing to notice here is the defitinions of the uris of the virtual sites. This is where you can tell it to associate files with tomcat. In our case, any file which ends in .jsp will be passed to tomcat.
/etc/tomcat/jk2.properties
# jk2.properties # Configured for channel UNIX # Set the desired handler list handler.list=apr,request,channelUnix # UNIX Domain socket location channelUnix.file=/usr/local/tomcat/work/jk2.socket # Dynamic library serverRoot=/etc/httpd apr.NativeSo=/usr/local/httpd/modules/jkjni.so #channelSocket.port=8009 |
Notice here how the sockets ports are commented out, since we're using file channels instead. Also notice here the loading of the jkjni.so module. This is the one which was renamed previously.
/etc/tomcat/server.xml
<!-- Example Server Configuration File -->
<!-- Note that component elements are nested corresponding to their
parent-child relationships with each other -->
<Server port="8005" shutdown="SHUTDOWN" debug="0">
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"
debug="0"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
debug="0"/>
<!-- Global JNDI resources -->
<GlobalNamingResources>
<!-- Test entry for demonstration purposes -->
<Environment name="simpleValue" type="java.lang.Integer" value="30"/>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users -->
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved">
</Resource>
<ResourceParams name="UserDatabase">
<parameter>
<name>factory</name>
<value>org.apache.catalina.users.MemoryUserDatabaseFactory</value>
</parameter>
<parameter>
<name>pathname</name>
<value>conf/tomcat-users.xml</value>
</parameter>
</ResourceParams>
</GlobalNamingResources>
<!-- Define the Tomcat Stand-Alone Service -->
<Service name="Catalina">
<!-- Define a non-SSL Coyote HTTP/1.1 Connector on port 8080 -->
<Connector port="8080"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true" />
<!-- Note : To disable connection timeouts, set connectionTimeout value
to 0 -->
<!-- Define a Coyote/JK2 AJP 1.3 Connector on port 8009 -->
<Connector port="8009"
enableLookups="false" redirectPort="8443" debug="0"
protocol="AJP/1.3" />
<!-- Define the top level container in our container hierarchy -->
<Engine name="Catalina" defaultHost="localhost" debug="0">
<!-- Global logger unless overridden at lower levels -->
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="catalina_log." suffix=".txt"
timestamp="true"/>
<!-- Because this Realm is here, an instance will be shared globally -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
debug="0" resourceName="UserDatabase"/>
<!-- Define the default virtual host -->
<Host name="localhost" debug="0" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
<Context path="" docBase="/usr/local/tomcat/webapps/ROOT/" debug="0" reloadable="true" crossContext="true"/>
<Logger className="org.apache.catalina.logger.FileLogger"
directory="logs" prefix="localhost_log." suffix=".txt"
timestamp="true"/>
</Host>
<!-- perth-agentcity.csse.uwa.edu.au -->
<Host name="perth-agentcity.csse.uwa.edu.au" debug="1"
appBase="/home/projects/misc/perth-agentcity/public_html"
unpackWARs="true">
<!-- <Alias>perth-agentcity.csse.uwa.edu.au</Alias> -->
<Logger className="org.apache.catalina.logger.FileLogger"
directory="logs" prefix="perth-agentlog." suffix=".txt"
timestamp="true"/> -->
<!-- Root Context -->
<Context path="" docBase="/home/projects/misc/perth-agentcity/public_html" debug="1"
reloadable="true" crossContext="true" />
</Host>
<!-- projects.csse.uwa.edu.au -->
<Host name="projects.csse.uwa.edu.au" debug="1"
appBase="/usr/local/httpd/htdocs"
unpackWARs="true">
<Logger className="org.apache.catalina.logger.FileLogger"
directory="logs" prefix="projects." suffix=".txt"
timestamp="true"/> -->
<Context path="" docBase="/usr/local/httpd/htdocs" debug="1"
reloadable="true" crossContext="true" />
</Host>
</Engine>
</Service>
</Server>
|
I've stripped out all most of the comments, but there should be a template one you can follow in your Tomcat configuration. About all you'll need to do is edit the file paths and make sure they match up. Any virtual hosts you want need to be added to the bottom so the base directories are defined and that appears to be all you need to do.
Once you have set all of those, start it up and give it a test. A test .jsp file you can use will look like:
<HTML> <BODY> <H1><%= "It works" %></h1><%= "at " + java.util.Calendar.getInstance().getTime() %> </BODY> </HTML> |
You should see the message "It works" on the screen along with the current date. If you don't see that, then you've got problems.
DEBUGGING
My biggest problem was missing libraries. This was evident when tomcat was starting. The logs had a line:
INFO: APR not loaded, disabling jni components: java.io.IOException: java.lang.UnsatisfiedLinkError: /usr/local/httpd-2.0.49/modules/jkjni.so: /usr/local/httpd-2.0.49/modules/jkjni.so: undefined symbol: apr_md5_final
in them. If you see anything similiar and APR is not loading, then your .jsp files are not going to work. To
solve the library problem, use the apu-config command as has been detailed above. You can also check with the ldd
command to see what libraries have been compiled in.
|
# ldd /usr/local/httpd/modules/jkjni.so libcrypt.so.1 => /lib/libcrypt.so.1 (0x40046000) libapr-0.so.0 => /usr/local/httpd-2.0.49/lib/libapr-0.so.0 (0x40074000) libaprutil-0.so.0 => /usr/local/httpd-2.0.49/lib/libaprutil-0.so.0 (0x40097000) libgdbm.so.2 => /usr/lib/libgdbm.so.2 (0x400ab000) libdb-4.0.so => /lib/libdb-4.0.so (0x400b2000) libexpat.so.0 => /usr/lib/libexpat.so.0 (0x4015a000) libc.so.6 => /lib/i686/libc.so.6 (0x4017a000) librt.so.1 => /lib/i686/librt.so.1 (0x402b4000) libm.so.6 => /lib/i686/libm.so.6 (0x402c6000) libnsl.so.1 => /lib/libnsl.so.1 (0x402e8000) libpthread.so.0 => /lib/i686/libpthread.so.0 (0x402fd000) libdl.so.2 => /lib/libdl.so.2 (0x4034d000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000) |
Useful links: