This article is a step by step guide for installing Apache Tomcat 6.0 (6.0.18) on 64-bit Debian Linux 4.0. It covers the setup of multiple Tomcat JVM instances on a single Linux server. The instructions in this guide are applicable to most other Linux distributions.
# mkdir -p /usr/java # cd /usr/java # # chmod 700 /tmp/jdk-6u10-linux-x64.bin # /tmp/jdk-6u10-linux-x64.bin ... creating: jdk1.6.0_10/ creating: jdk1.6.0_10/db/ creating: jdk1.6.0_10/db/bin/ inflating: jdk1.6.0_10/db/bin/ij inflating: jdk1.6.0_10/db/bin/NetworkServerControl inflating: jdk1.6.0_10/db/bin/setNetworkClientCP.bat inflating: jdk1.6.0_10/db/bin/derby_common.sh ... Done. # export JAVA_HOME=/usr/java/jdk1.6.0_10 # export PATH=$JAVA_HOME/bin:$PATH # # which java /usr/java/jdk1.6.0_10/bin/java # java -version java version "1.6.0_10" Java(TM) SE Runtime Environment (build 1.6.0_10-b33) Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode) #
# md5sum /tmp/apache-tomcat-6.0.18.tar.gz 8354e156f097158f8d7b699078fd39c1 /tmp/apache-tomcat-6.0.18.tar.gzInstalling Tomcat from a binary release (tar file) requires manual creation of the Tomcat user account. This is not necessary if you install the Tomcat RPM package on a Linux system that supports RPMs.
# groupadd tomcat # useradd -g tomcat -s /usr/sbin/nologin -m -d /home/tomcat tomcat(It should be noted that other Linux systems have nologin under /sbin not /usr/sbin)
# cd /var/lib # tar zxvf /tmp/apache-tomcat-6.0.18.tar.gz # chown -R tomcat.tomcat /var/lib/apache-tomcat-6.0.18The get the Tomcat version of the newly installed Tomcat, run:
# /var/lib/apache-tomcat-6.0.18/bin/version.sh Using CATALINA_BASE: /var/lib/apache-tomcat-6.0.18 Using CATALINA_HOME: /var/lib/apache-tomcat-6.0.18 Using CATALINA_TMPDIR: /var/lib/apache-tomcat-6.0.18/temp Using JRE_HOME: /usr Server version: Apache Tomcat/6.0.18 Server built: Jul 22 2008 02:00:36 Server number: 6.0.18.0 OS Name: Linux OS Version: 2.6.18-6-amd64 Architecture: x86_64 JVM Version: 1.4.2 JVM Vendor: Free Software Foundation, Inc. #Starting/Stopping Tomcat
# export JAVA_HOME=/usr/java/jdk1.6.0_10 # export PATH=$JAVA_HOME/bin:$PATH # export CATALINA_HOME=/var/lib/apache-tomcat-6.0.18 # export CATALINA_BASE=/var/lib/apache-tomcat-6.0.18 # # su -p -s /bin/sh tomcat $CATALINA_HOME/bin/startup.sh Using CATALINA_BASE: /var/lib/apache-tomcat-6.0.18 Using CATALINA_HOME: /var/lib/apache-tomcat-6.0.18 Using CATALINA_TMPDIR: /var/lib/apache-tomcat-6.0.18/temp Using JRE_HOME: /usr/java/jdk1.6.0_10 #Now verify that Tomcat was started successfully by opening the URL http://localhost:8080 (Port number 8080 is the default port used by Tomcat). Note that you should also be able to use the name of your server instead of localhost. Once you opened the URL in your browser you should see Tomcat's Congratulation page. If you don't see the page, check the log files under $CATALINA_HOME/logs (/var/lib/apache-tomcat-6.0.18/logs).
# su -p -s /bin/sh tomcat $CATALINA_HOME/bin/shutdown.sh Using CATALINA_BASE: /var/lib/apache-tomcat-6.0.18 Using CATALINA_HOME: /var/lib/apache-tomcat-6.0.18 Using CATALINA_TMPDIR: /var/lib/apache-tomcat-6.0.18/temp Using JRE_HOME: /usr/java/jdk1.6.0_10 #Switching to Tomcat User Account
# su - -s /bin/sh tomcat $ id uid=1001(tomcat) gid=1001(tomcat) groups=1001(tomcat) $Note that non-root users cannot switch to the tomcat account.
# mkdir -p /opt/tomcat-instance/sales.example.com # cd /opt/tomcat-instance/sales.example.com # # cp -a /var/lib/apache-tomcat-6.0.18/conf . # mkdir common logs temp server shared webapps work # # chown -R tomcat.tomcat /opt/tomcat-instanceMost of the remaining steps are executed as the tomcat user. So make sure you switch from root to tomcat:
# su - -s /bin/sh tomcat $ id uid=1001(tomcat) gid=1001(tomcat) groups=1001(tomcat) $Next I created an environment file for the new Tomcat instance. This will be useful for easily setting the environment variables when starting/stopping the new Tomcat instance:
$ cat > /opt/tomcat-instance/sales.env << EOF export JAVA_HOME=/usr/java/jdk1.6.0_10 export PATH=\$JAVA_HOME/bin:\$PATH export CATALINA_HOME=/var/lib/apache-tomcat-6.0.18 export CATALINA_BASE=/opt/tomcat-instance/sales.example.com EOF $ $ cat /opt/tomcat-instance/sales.env export JAVA_HOME=/usr/java/jdk1.6.0_10 export PATH=$JAVA_HOME/bin:$PATH export CATALINA_HOME=/var/lib/apache-tomcat-6.0.18 export CATALINA_BASE=/opt/tomcat-instance/sales.example.com $CATALINA_HOME is the base directory of Tomcat that contains all the libraries, scripts etc. for Tomcat. This is the parent directory of the extracted Tomcat tar file.
<Server port="8005" shutdown="SHUTDOWN"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />However, these port numbers will have to be changed for the second Tomcat instance though, see Steps for Second Tomcat JVM Instance and Application.
$ source /opt/tomcat-instance/sales.env $ $CATALINA_HOME/bin/startup.sh Using CATALINA_BASE: /opt/tomcat-instance/sales.example.com Using CATALINA_HOME: /var/lib/apache-tomcat-6.0.18 Using CATALINA_TMPDIR: /opt/tomcat-instance/sales.example.com/temp Using JRE_HOME: /usr/java/jdk1.6.0_10 $If everything has been configured correctly, you should now see an empty white page when opening the URL http://localhost:8080. Note that instead of localhost you should also be able to use the name of your server.
# iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080 # iptables -t nat -I OUTPUT -p tcp --dport 80 -j REDIRECT --to-ports 8080The first rule redirects incoming requests on port 80 generated from other computer nodes, and the second rule redirects incoming requests on port 80 generated from the local node where Tomcat is running.
# iptables -t nat -L Chain PREROUTING (policy ACCEPT) target prot opt source destination REDIRECT tcp -- anywhere anywhere tcp dpt:www redir ports 8080 Chain POSTROUTING (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination REDIRECT tcp -- anywhere anywhere tcp dpt:www redir ports 8080 #To remove the NAT rules we just created, you can run the iptables -t nat -F command which flushes and deletes the rules. Note that this will also flush any other rules that may have been configured on your system! For more information on iptables, see netfilter/iptables documentation.
# iptables-save > /etc/iptables.confThen edit the /etc/network/interfaces file and add the line highlighted in blue for the public network interface. For example:
iface eth0 inet static address 192.168.1.23 netmask 255.255.255.0 network 192.168.1.0 broadcast 192.168.1.255 gateway 192.168.1.1 pre-up iptables-restore < /etc/iptables.confThe pre-up configuration in this example activates the iptables rules on my system before the public interface eth0 comes up. So the rules can be seen with iptables -t nat -L after each reboot. Note that for security reasons it's important that firewall rules are established before the network interfaces come up. Even though this is not an issue for relaying Tomcat connections, as a matter of good practice, the iptables rules should always be established before the network comes up.
<Connector port="8080" protocol="HTTP/1.1" proxyPort="80" connectionTimeout="20000" redirectPort="8443" />After that you need to restart Tomcat to make this change effective.
# su - -s /bin/sh tomcat $ source /opt/tomcat-instance/sales.envSetting up Web Application Layout
$ mkdir $CATALINA_BASE/webapps/salesConfiguring Web Application
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> <Context docBase="sales" path="/mysales"/>In this example you can see that appBase already points to webapps by default, that is $CATALINA_BASE/webapps. The newly added path attribute points to the sales directory under $CATALINA_BASE/webapps which is the location for the new application. And the docBase attribute is set to mysales which stands for the application name within the URL, i.e. "http://localhost/mysales" or "http://localhost:8080/mysales". Make sure to add this new Context element inside the Host container element for 'localhost' which is the default host name.
$ cat > $CATALINA_BASE/webapps/sales/index.html << EOF <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD><META http-equiv=Content-Type content="text/html"></HEAD> <BODY> <H3>Apache Tomcat Sales Home Page</H3> </BODY> </HTML> EOF $
$ source /opt/tomcat-instance/sales.env $ $CATALINA_HOME/bin/shutdown.sh $ $CATALINA_HOME/bin/startup.shIf everything was configured correctly, you should now see the default home page for the new web application when opening the URL http://localhost/mysales or http://localhost/mysales:8080. Instead of localhost you should also be able to use the name of your server. If you get the error 'java.net.ConnectException: Connection refused' when you shutdown Tomcat, then Tomcat was probably not running. If you don't see the home page, check the log files under $CATALINA_BASE/logs.
$ mkdir -p $CATALINA_BASE/webapps/sales/WEB-INF/classesJAR Files
$ mkdir $CATALINA_BASE/webapps/sales/WEB-INF/libThe Java servlet example below requires the servlet-api.jar JAR file. This JAR is already available in the Tomcat distribution directory tree $CATALINA_HOME/lib. You could copy this JAR file to the application's new lib directory $CATALINA_BASE/webapps/sales/WEB-INF/lib, but then you would get the following warning in the $CATALINA_BASE/logs/catalina.out log file when you startup Tomcat:
$ cat $CATALINA_BASE/webapps/sales/WEB-INF/classes/Sales.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class Sales extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Sales Page</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Executing Sales ...</h1>"); out.println("</body>"); out.println("</html>"); } }To compile the new Java servlet, the servlet-api.jar JAR file is needed which can be specified with either the -classpath option or the CLASSPATH environment variable. The -classpath option for SDK tools is preferred over the CLASSPATH environment variable since it can be set individually for each application without affecting others. In the following example I specify the path of the class directory with the basename '*' (if you are unfamiliar with basename, see 'man basename'). This is equivalent to specifying all files with the extensions .jar or .JAR files in the directory and therefore individual JAR files like servlet-api.jar don't need to be specified.
$ cd $CATALINA_BASE/webapps/sales/WEB-INF/classes $ javac -classpath "$CATALINA_HOME/lib/*" Sales.java $ ls Sales.class Sales.java $Configuring the Java Servlet
$CATALINA_BASE/conf/web.xml $CATALINA_BASE/webapps/{your-appname}/WEB-INF/web.xmlThe first one is the default web.xml file which is the base for all web applications in a Tomcat JVM instance, and the latter one is for the web application where WEB-INF resides for overwriting application specific settings.
$ cat $CATALINA_BASE/webapps/sales/WEB-INF/web.xml <?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>servlet_sales</servlet-name> <servlet-class>Sales</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet_sales</servlet-name> <url-pattern>/execute</url-pattern> </servlet-mapping> </web-app>For each servlet there is a <servlet> element. It identifies the servlet name (<servlet-name>) and the Java class name (<servlet-class>). The servlet mapping (<servlet-mapping>) maps a URI to the servlet name (<servlet-name>). In the above example "/execute" in "http://localhost:8080/mysales/execute" maps to "servlet_sales" which points to the "Sales" servlet class. Note that the order of these elements is important. So when you open the URL "http://localhost:8080/mysales/execute", the "Sales" Java servlet will be executed.
$ cat $CATALINA_BASE/webapps/sales/index.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD><META http-equiv=Content-Type content="text/html"></HEAD> <BODY> <H3>Apache Tomcat Sales Home Page</H3> <a href="/mysales/execute">Execute Sales</a> </BODY> </HTML> $
# su - -s /bin/sh tomcat $ source /opt/tomcat-instance/sales.env $ $CATALINA_HOME/bin/shutdown.sh $ $CATALINA_HOME/bin/startup.shAfter Tomcat restarted, open the URL http://localhost/mysales (or use the server name instead of localhost) and you should see the "Execute Sales" link. Clicking on this link should invoke the Java servlet and display "Executing Sales" in your browser. If you are presented with an empty page instead, review the above steps and make sure you didn't miss a step. Check also the log files under $CATALINA_BASE/logs.
# mkdir -p /opt/tomcat-instance/order.example.com # cd /opt/tomcat-instance/order.example.com # # cp -a /var/lib/apache-tomcat-6.0.18/conf . # mkdir common logs temp server shared webapps work # # chown -R tomcat.tomcat /opt/tomcat-instance/order.example.com # # su - -s /bin/sh tomcat $ cat > /opt/tomcat-instance/order.env << EOF export JAVA_HOME=/usr/java/jdk1.6.0_10 export PATH=\$JAVA_HOME/bin:\$PATH export CATALINA_HOME=/var/lib/apache-tomcat-6.0.18 export CATALINA_BASE=/opt/tomcat-instance/order.example.com EOF $ $ source /opt/tomcat-instance/order.env $For the second Tomcat JVM instance the default port numbers need to be changed in $CATALINA_BASE/conf/server.xml (/opt/tomcat-instance/order.example.com/conf/server.xml). In the following example I increased the port numbers by one:
<Server port="8006" shutdown="SHUTDOWN"> <Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8444" /> <Connector port="8010" protocol="AJP/1.3" redirectPort="8444" />Create a new application root directory:
$ mkdir $CATALINA_BASE/webapps/orderTo configure the new web application, edit $CATALINA_BASE/conf/server.xml (/opt/tomcat-instance/order.example.com/conf/server.xml) and add the following entry in blue:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> <Context docBase="order" path="/myorder"/>Create a new home page for the new "Order" application and include a link to the Java servlet that will be setup next:
$ cat > $CATALINA_BASE/webapps/order/index.html << EOF <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD><META http-equiv=Content-Type content="text/html"></HEAD> <BODY> <H3>Apache Tomcat Order Home Page</H3> <a href="/myorder/execute">Execute Order</a> </BODY> </HTML> EOF $Now setup and create a new Java servlet:
$ mkdir -p $CATALINA_BASE/webapps/order/WEB-INF/classes $ mkdir $CATALINA_BASE/webapps/order/WEB-INF/lib
$ cat $CATALINA_BASE/webapps/order/WEB-INF/classes/Order.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class Order extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Order Page</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Executing Order ...</h1>"); out.println("</body>"); out.println("</html>"); } }Compile the new Java servlet:
$ cd $CATALINA_BASE/webapps/order/WEB-INF/classes $ javac -classpath "$CATALINA_HOME/lib/*" Order.java $ ls Order.class Order.java $Configure the Java servlet:
$ cat $CATALINA_BASE/webapps/order/WEB-INF/web.xml <?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>servlet_order</servlet-name> <servlet-class>Order</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet_order</servlet-name> <url-pattern>/execute</url-pattern> </servlet-mapping> </web-app>Now make sure to relogin as tomcat and start the second Tomcat JVM instance:
# su - -s /bin/sh tomcat $ source /opt/tomcat-instance/order.env $ $CATALINA_HOME/bin/startup.shAfter the second Tomcat JVM restarted, open the URL http://localhost:8081/myorder (or use the server name instead of localhost) and you should see the "Execute Order" link. Clicking on this link should invoke the Java servlet and display "Executing Order" in your browser. If you are presented with an empty page instead, review the above steps and make sure you didn't miss a step. Check also the log files under $CATALINA_BASE/logs.