These notes are about installing Tomcat in a production environment under apache. This notes were taken while I were installing such product in a machine on a DMZ, so security were my first concern in every step I took.
Said that, it is possible that the document has misunderstandings and errors. Nobody is perfect. Use it at your own risk.
The machine I am using is a Virtual Server with 32 bits and a SuSE 11.1 installed.
You should have the JRE installed in your machine. You can download it from Oracle website.
Make sure that you have defined a environmen variable JRE_HOME that points to the location of the JRE. In other words, this command should work:
rluna@machine:~> ($JRE_HOME/bin/java -version) java version "1.6.0_22" Java(TM) SE Runtime Environment (build 1.6.0_22-b04) Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode)
Yes, the version of java is a bit outdated. I've used the version that the current version of linux provided through the package manager.
The idea is to create a “tomcat” user and a “tomcat” group, own all the files of tomcat with this user and run the service with this user: this prevent that, in case of god-knows-what, an attacker would gain root privileges easily.
useradd --create-home --user-group --system -g tomcat tomcat
The –system
option is to specify that the user must be a system account.
The -g
is to specify that the default group for this account must be tomcat
instead users
, as used to be. And finnaly the -m
option is for creating a home directory. I prefer to create a home directory for this type of users, just for store there certain downloads or configuration files.
As you may know, if you want to login as the user tomcat
all you have to do is to change the shell:
useradd -s /bin/bash tomcat
and, to return the user to the prior state, you only have to do the following:
useradd -s /bin/false tomcat
This can be checked out entering as the tomcat user or checking the /etc directory. This is for not leaving open files to every other user in the system.
I've choose /usr/local/share as the main directory. I've created a directory called apache-tomcat-7.0.22
-this is the version I am using- and a link to this named tomcat
: the rest of the commands, or services will be refered to the /usr/local/share/tomcat
dir. With this resource, it will be easy to upgrade tomcat simply by changing the link.
mkdir apache-tomcat-7.0.22 chown tomcat:tomcat apache-tomcat-7.0.22 chmod 750 apache-tomcat-7.0.22 ln -s apache-tomcat-7.0.22 tomcat
Copy all the contents into the new location (or uncompress them), and make sure that the permissions are assigned to tomcat:tomcat and are the proper.
cp /home/tomcat/tmp/apache-tomcat-7.0.22/* . -R chown tomcat:tomcat * -R
I've seen that the Windows .bat files are in the /bin files. I suggest delete them.
At this point, tomcat should start with the default configuration. It is a good idea to make a little test prior to further testing.
Log in as the tomcat user and run the server:
tomcat@machine:/usr/local/share/apache-tomcat-7.0.22/bin> ./startup.sh Using CATALINA_BASE: /usr/local/share/apache-tomcat-7.0.22 Using CATALINA_HOME: /usr/local/share/apache-tomcat-7.0.22 Using CATALINA_TMPDIR: /usr/local/share/apache-tomcat-7.0.22/temp Using JRE_HOME: /usr Using CLASSPATH: /usr/local/share/apache-tomcat-7.0.22/bin/bootstrap.jar:/usr/local/share/apache-tomcat-7.0.22/bin/tomcat-juli.jar
Open a web browser and point it to the http://localhost:8080 port. It should show a welcome message of tomcat. If not, check out what is wrong. A simple lynx http://localhost:8080
should return something understandable.
SuSE has all their log files under /var/log, so I prefer respect this practice and move the logs of apache to this location. Now they are under /usr/local/share/tomcat/logs.
First, create a proper directory under /var/log, let's say /var/log/tomcat:
# mkdir /var/log/tomcat # chown tomcat:tomcat /var/log/tomcat
Then, open the file CATALINA_HOME/conf/logging.properties –CATALINA_HOME is the directory Tomcat is installed, and is refered as this in the documentation– and modify the following entries:
1catalina.org.apache.juli.FileHandler.level = FINE 1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 1catalina.org.apache.juli.FileHandler.prefix = catalina. 2localhost.org.apache.juli.FileHandler.level = FINE 2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 2localhost.org.apache.juli.FileHandler.prefix = localhost.
When it appears ${catalina.base}/logs it should appear the new directory, /var/log/tomcat.
Open the “server.xml” file and change locate the “logs” old directory and replace by the new one, /var/log/tomcat. I've replace the following entries:
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt"
Go to the bin
directory and open the file catalina.sh
. There is a configuration for the console of the server there. Locate this entry:
if [ -z "$CATALINA_OUT" ] ; then CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out fi
And change for:
if [ -z "$CATALINA_OUT" ] ; then CATALINA_OUT=/var/log/tomcat/catalina.out fi
Delete the content of the “logs” directory and start again the server. If after running the server still appear content, you should check the configuration or the configuration.
If the checking were successful, remove the logs
directory and create a symbolic link with the same name: just in case other user logged in the system and searched for the directory where it is supposed to be in a normal installation.
Another step is to change the location of the config files and put them under /etc/tomcat
: it is the usual point where a normal user should look for.
machine:/etc # mkdir tomcat machine:/etc # chown tomcat:tomcat tomcat
Log in as the tomcat user:
tomcat@machine:/usr/local/share/tomcat/conf> cp * /etc/tomcat/ -R tomcat@machine:/usr/local/share/tomcat> tar -czf conf_orig.tgz conf/ tomcat@machine:/usr/local/share/tomcat> rm -r conf tomcat@machine:/usr/local/share/tomcat> ln -s /etc/tomcat/ conf
In general, it is a good idea to create a service that will start automatically when the server starts. And that will be gently stopped when the servers is shut down.
How to do this??
One idea is to search in internet. But bear in mind that most modern Linux distributions comes with examples of services ready to customize for your needs. These examples are common called as skeletons
and normally live –or rest, because they are skeletons, aren't they??– in /etc.
Mess around the /etc directory of your installation or check /etc/rc.d/ or /etc/init.d in order to locate those scripts.
Here I put the script I created for SuSE
#!/bin/sh # # Script for start/stop tomcat. Based on template "skeleton" # # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or (at # your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, # USA. # # /etc/init.d/FOO # and its symbolic link # /(usr/)sbin/rcFOO # # # LSB compatible service control script; see http://www.linuxbase.org/spec/ # # ### BEGIN INIT INFO # Provides: tomcat # Required-Start: $syslog $remote_fs apache # Should-Start: $time ypbind smtp # Required-Stop: $syslog $remote_fs # Should-Stop: # Default-Start: 3 5 # Default-Stop: 0 1 2 6 # Short-Description: Tomcat # Description: Start the Tomcat Application Server ### END INIT INFO # # Any extensions to the keywords given above should be preceeded by # X-VendorTag- (X-UnitedLinux- X-SuSE- for us) according to LSB. # # Notes on Required-Start/Should-Start: # * There are two different issues that are solved by Required-Start # and Should-Start # (a) Hard dependencies: This is used by the runlevel editor to determine # which services absolutely need to be started to make the start of # this service make sense. Example: nfsserver should have # Required-Start: $portmap # Also, required services are started before the dependent ones. # The runlevel editor will warn about such missing hard dependencies # and suggest enabling. During system startup, you may expect an error, # if the dependency is not fulfilled. # (b) Specifying the init script ordering, not real (hard) dependencies. # This is needed by insserv to determine which service should be # started first (and at a later stage what services can be started # in parallel). The tag Should-Start: is used for this. # It tells, that if a service is available, it should be started # before. If not, never mind. # * When specifying hard dependencies or ordering requirements, you can # use names of services (contents of their Provides: section) # or pseudo names starting with a $. The following ones are available # according to LSB (1.1): # $local_fs all local file systems are mounted # (most services should need this!) # $remote_fs all remote file systems are mounted # (note that /usr may be remote, so # many services should Require this!) # $syslog system logging facility up # $network low level networking (eth card, ...) # $named hostname resolution available # $netdaemons all network daemons are running # The $netdaemons pseudo service has been removed in LSB 1.2. # For now, we still offer it for backward compatibility. # These are new (LSB 1.2): # $time the system time has been set correctly # $portmap SunRPC portmapping service available # UnitedLinux extensions: # $ALL indicates that a script should be inserted # at the end # * The services specified in the stop tags # (Required-Stop/Should-Stop) # specify which services need to be still running when this service # is shut down. Often the entries there are just copies or a subset # from the respective start tag. # * Should-Start/Stop are now part of LSB as of 2.0, # formerly SUSE/Unitedlinux used X-UnitedLinux-Should-Start/-Stop. # insserv does support both variants. # * X-UnitedLinux-Default-Enabled: yes/no is used at installation time # (%fillup_and_insserv macro in %post of many RPMs) to specify whether # a startup script should default to be enabled after installation. # It's not used by insserv. # # Note on runlevels: # 0 - halt/poweroff 6 - reboot # 1 - single user 2 - multiuser without network exported # 3 - multiuser w/ network (text mode) 5 - multiuser w/ network and X11 (xdm) # # Note on script names: # http://www.linuxbase.org/spec/refspecs/LSB_1.3.0/gLSB/gLSB/scrptnames.html # A registry has been set up to manage the init script namespace. # http://www.lanana.org/ # Please use the names already registered or register one or use a # vendor prefix. TOMCAT_HOME=/usr/local/share/tomcat test -d $TOMCAT_HOME || { echo "$TOMCAT_HOME is not a directory. Please check." ; if [ "$1" = "stop" ]; then exit 0; else exit 5; fi; } # Check for missing binaries (stale symlinks should not happen) # Note: Special treatment of stop for LSB conformance TOMCAT_BIN=$TOMCAT_HOME/lib/catalina.jar test -s $TOMCAT_BIN || { echo "$TOMCAT_BIN not found. Is tomcat properly install ed?"; if [ "$1" = "stop" ]; then exit 0; else exit 5; fi; } # Check for existence of needed config file and read it TOMCAT_CONFIG=$TOMCAT_HOME/conf/server.xml test -r $TOMCAT_CONFIG || { echo "$TOMCAT_CONFIG not exists or not readable"; if [ "$1" = "stop" ]; then exit 0; else exit 6; fi; } # Source LSB init functions # providing start_daemon, killproc, pidofproc, # log_success_msg, log_failure_msg and log_warning_msg. # This is currently not used by UnitedLinux based distributions and # not needed for init scripts for UnitedLinux only. If it is used, # the functions from rc.status should not be sourced or used. #. /lib/lsb/init-functions # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status # rc_status -v be verbose in local rc status and clear it afterwards # rc_status -v -r ditto and clear both the local and overall rc status # rc_status -s display "skipped" and exit with status 3 # rc_status -u display "unused" and exit with status 3 # rc_failed set local and overall rc status to failed # rc_failed <num> set local and overall rc status to <num> # rc_reset clear both the local and overall rc status # rc_exit exit appropriate to overall rc status # rc_active checks whether a service is activated by symlinks . /etc/rc.status # Reset status of this service rc_reset # Return values acc. to LSB for all commands but status: # 0 - success # 1 - generic or unspecified error # 2 - invalid or excess argument(s) # 3 - unimplemented feature (e.g. "reload") # 4 - user had insufficient privileges # 5 - program is not installed # 6 - program is not configured # 7 - program is not running # 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl) # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signaling is not supported) are # considered a success. case "$1" in start) echo -n "Starting Tomcat " ## Start daemon with startproc(8). If this fails ## the return value is set appropriately by startproc. #/sbin/startproc -u tomcat -g tomcat $TOMCAT_HOME/bin/startup.sh su tomcat -c $TOMCAT_HOME/bin/startup.sh # Remember status and be verbose rc_status -v ;; stop) echo -n "Shutting down Tomcat " ## Stop daemon with killproc(8) and if this fails ## killproc sets the return value according to LSB. #/sbin/startproc -u tomcat -g tomcat $TOMCAT_HOME/bin/shutdown.sh su tomcat -c $TOMCAT_HOME/bin/shutdown.sh # Remember status and be verbose rc_status -v ;; restart) ## Stop the service and regardless of whether it was ## running or not, start it again. $0 stop $0 start # Remember status and be quiet rc_status ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 ;; esac rc_exit
Due to the fact that I am using apache at the same time in the same machine, Tomcat will act only as the server of the JSP pages, delegating all the static content to apache.
You have to have apxs
installed in your system. If you are running apache, it is achieved installing through yast the module apache2-devel
.
The only way to integrate apache with tomcat is to use mod_jk. Here is the documentation:
http://tomcat.apache.org/connectors-doc/webserver_howto/apache.html
And you have to google the download location. I've downloaded the source code and here are the instructions to compile it:
Once you have the apxs2 program installed and the source code of the mod_jk, you are prepared to compile it:
$ cd native $ ./configure --with-apxs=/usr/sbin/apxs2 $ su # make install
http://tomcat.apache.org/connectors-doc-archive/jk2/jk/quickhowto.html
In the apache configuration directory, create a file called “workers.properties” with the following content:
# Define 1 real worker using ajp13 worker.list=worker1 # Set properties for worker1 (ajp13) worker.worker1.type=ajp13 worker.worker1.host=localhost worker.worker1.port=8009 worker.worker1.lbfactor=50 worker.worker1.cachesize=10 worker.worker1.cache_timeout=600 worker.worker1.socket_keepalive=1 worker.worker1.socket_timeout=300
At least the following configuration must be put under apache:
# Load mod_jk module # Under SuSE this is carried out by sysconfig/apache2 # Update this path to match your modules location LoadModule jk_module libexec/mod_jk.so # Under SuSE this is carried out by sysconfig/apache2 # Declare the module for <IfModule directive> AddModule mod_jk.c # Where to find workers.properties # Update this path to match your conf directory location (put workers.properties next to httpd.conf) JkWorkersFile /etc/httpd/conf/workers.properties # Where to put jk logs # Update this path to match your logs directory location (put mod_jk.log next to access_log) JkLogFile /var/log/httpd/mod_jk.log # Set the jk log level [debug/error/info] JkLogLevel info # Select the log format JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " # JkOptions indicate to send SSL KEY SIZE, JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories # JkRequestLogFormat set the request format JkRequestLogFormat "%w %V %T" # Send everything for context /examples to worker named worker1 (ajp13) JkMount /examples/* worker1 # In installation with virtual servers, it allows to respond to # http://wateverthedomainwillbe/examples # If not, you have to put this directive (JkMountCopy) under # the VirtualHost directive you want to use JkMountCopy All
There are several ways to organize it. Under SuSE, the best way is the following:
/etc/sysconfig/apache2
modify the line APACHE_MODULES
and add at the end the “jk”: this will instruct to load the mod_jk.so module also and modify /etc/apache2/sysconfig/loadmodule.conf according to thatAPACHE_CONF_INCLUDE_FILES
to include a file that will be called mod_jk.conf
Disconnect the default Connector port under tomcat: the port 8080. If you aren't gonna use it, the obvious is to disconnect it.
Under TOMCAT_HOME, locate the file server.xml and comment out the following lines:
<!-- Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" / -->
Go to TOMCAT_HOME/webapps and delete the directory “examples”. Why? Because is a well-known application that do things. Some example applications aren't built with security in mind, so it is a good idea to delete them.
Test, test, test… In every step you take in this issue, try to test if you are doing the correct!!! This is the best advice I can give you in order to succeed in such projects.
Anyway, the last step is to test the issue. I've opened a browser, point it to http://mydomain.com/examples/whateveryouwant and you should have a fantastic error screen directly from tomcat (instead of a 404 coming from apache).
You can elaborate this much –as I did– and change the “examples” you find in the mod_jk.conf file for “docs”: this will point to an application called “docs” that is in Tomcat. If you do this, you cant point your browser to http://mydomain.com/docs/index.html and get the tomcat documentation that comes with the tomcat installation:
In this document I've tried to explain how to install tomcat to serve as a backend for an Apache http server, so it serves only certain types of pages.
The explanation is made from the ground, as if there were no prior knowledge of apache nor tomcat. I hope I achieved this. If not, drop me some lines in the Discussion below. Anyway, any comment or suggestion will help.
I checked out this document: http://www.digitalsanctum.com/2007/08/18/20-tips-for-using-tomcat-in-production/. Unless it is a bit outdated (2007), many of the ideas depicted there are still valid.
Of course, I checked also the Apache Tomcat documentation: http://tomcat.apache.org/tomcat-7.0-doc/index.html
And have a look at this: http://tomcat.apache.org/connectors-doc/reference/apache.html. It is the documentation of the mod_jk module and it is very important if you want to have your own installation.
~~DISQUS~~