Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

第 46 章 Apache Tomcat

目錄

46.1. Tomcat 安裝與配置
46.1.1. Tomcat 6
46.1.1.1. tomcat-native
46.1.1.2. 啟動腳本
46.1.2. Tomcat 7
46.1.2.1. Server JRE
46.1.2.2. Tomcat
46.1.3. Java 8 + Tomcat 8
46.1.3.1. systemctl 啟動腳本
46.1.3.2. Session 共享
46.1.3.2.1. test session
46.1.4. 防火牆配置
46.1.5. 同時運行多實例
46.1.6. Testing file
46.1.7. mod_jk
46.1.8. mod_proxy_ajp
46.1.9. RewriteEngine 連接 Tomcat
46.1.10. SSL 雙向認證
46.2. 配置 Tomcat 伺服器
46.2.1. server.xml
46.2.1.1. Connector
46.2.1.1.1. HTTPS
46.2.1.1.2. compression
46.2.1.1.3. useBodyEncodingForURI
46.2.1.1.4. 隱藏Tomcat版本信息
46.2.1.2. Context
46.2.1.2.1. 應用程序安全
46.2.1.2.2. JSESSIONID
46.2.2. tomcat-users.xml
46.2.3. context.xml
46.2.3.1. Resources
46.2.3.2. session cookie
46.2.4. logging.properties
46.2.5. catalina.properties
46.3. 虛擬主機配置
46.3.1. 方案一
46.3.2. 方案二
46.3.3. Alias 別名
46.3.4. access_log
46.3.5. Context 配置
46.3.6. 主機綁定IP地址
46.4. SSI
46.5. Logging 日誌
46.5.1. 開啟 debug 模式
46.5.2. 切割 catalina.out 日誌
46.6. Init.d Script
46.6.1. Script 1
46.6.2. Shell Script 2

46.1. Tomcat 安裝與配置

46.1.1. Tomcat 6

解壓安裝

chmod +x jdk-6u1-linux-i586.bin
./jdk-6u1-linux-i586.bin
輸入"yes"回車

mv jdk1.6.0_01 /usr/local/
ln -s /usr/local/jdk1.6.0_01/ /usr/local/java
		

/etc/profile.d/java.sh

例 46.1. /etc/profile.d/java.sh

################################################
### Java environment
################################################
export JAVA_HOME=/usr/local/java
export JRE_HOME=/usr/local/java/jre
export PATH=$PATH:/usr/local/java/bin:/usr/local/java/jre/bin
export CLASSPATH="./:/usr/local/java/lib:/usr/local/java/jre/lib:/usr/local/memcached/api/java"
export JAVA_OPTS="-Xms512m -Xmx1024m"
			

下載binary解壓到/usr/local/

下載軟件包

wget http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.13/bin/apache-tomcat-6.0.13.tar.gz
wget http://archive.apache.org/dist/tomcat/tomcat-connectors/native/tomcat-native-1.1.10-src.tar.gz
wget http://archive.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.23/tomcat-connectors-1.2.23-src.tar.gz
		
tar zxvf apache-tomcat-6.0.13.tar.gz
mv apache-tomcat-6.0.13 /usr/local/
ln -s /usr/local/apache-tomcat-6.0.13/ /usr/local/tomcat
		

tomcat-native

tar zxvf tomcat-native-1.1.10-src.tar.gz
cd tomcat-native-1.1.10-src/jni/native
./configure --with-apr=/usr/local/apache/bin/apr-1-config --with-java-home=/usr/local/java/
make
make install
		

catalina.sh

CATALINA_OPTS="-Djava.library.path=/usr/local/apr/lib"
JAVA_OPTS="-Xss128k -Xms128m -Xmx1024m -XX:PermSize=128M -XX:MaxPermSize=256m -XX:MaxNewSize=256m"
		

啟動

startup.sh
		

46.1.1.1. tomcat-native

			
cd /usr/local/tomcat-6.0.18/bin
tar zxvf tomcat-native.tar.gz
cd tomcat-native-1.1.14-src/jni/native
./configure --with-apr=/usr/local/apr --with-java-home=/usr/java/jdk1.6.0_11
make && make install
			
			

46.1.1.2. 啟動腳本

例 46.2. /etc/init.d/tomcat

				
# cat /etc/init.d/tomcat
#!/bin/bash
# description: Tomcat Start Stop Restart
# processname: tomcat
# chkconfig: 234 20 80

JAVA_HOME=/srv/java
CATALINA_HOME=/srv/apache-tomcat

# Source function library.
. /etc/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

if [ -f /etc/sysconfig/tomcat ]; then
        . /etc/sysconfig/tomcat
fi

prog=tomcat
lockfile=/var/lock/subsys/$prog
pidfile=${PIDFILE-/var/run/$prog.pid}
lockfile=${LOCKFILE-/var/lock/subsys/$prog}
RETVAL=0
OPTIONS="--pidfile=${pidfile}"

start(){
        # Start daemons.
        echo -n $"Starting $prog: "
        #daemon $prog $OPTIONS
	$CATALINA_HOME/bin/startup.sh
	RETVAL=$?
        echo
	[ $RETVAL -eq 0 ] && touch $lockfile
	return $RETVAL

}

stop() {
	echo -n $"Stopping $prog: "
#	killproc -p ${pidfile} -d 10 $httpd
	$CATALINA_HOME/bin/shutdown.sh
	RETVAL=$?
	echo
	[ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
}

case $1 in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        start
        stop
    ;;
esac
exit 0
				
				

創建 /etc/init.d/tomcat 檔案,複製並粘貼上面的啟動腳本

vim /etc/init.d/tomcat
chmod +x /etc/init.d/tomcat
chkconfig --add tomcat
chkconfig --level 234 tomcat on
chkconfig --list tomcat
			

46.1.2. Tomcat 7

46.1.2.1. Server JRE

安裝 Server JRE

cd /usr/local/src/

tar zxvf server-jre-7u21-linux-x64.gz
mv jdk1.7.0_21 /srv/
ln -s /srv/jdk1.7.0_21 /srv/java
			

或者

curl -sS https://raw.github.com/netkiller/shell/master/java/server-jre.sh | bash
			

46.1.2.2. Tomcat

安裝下面步驟安裝Tomcat,注意不要使用root啟動tomcat。這裡使用www用戶啟動tomcat,這樣的目的是讓tomcat進程繼承www用戶權限。

			
cd /usr/local/src/
wget http://ftp.cuhk.edu.hk/pub/packages/apache.org/tomcat/tomcat-7/v7.0.40/bin/apache-tomcat-7.0.40.tar.gz
tar zxvf apache-tomcat-7.0.40.tar.gz

mv apache-tomcat-7.0.40 /srv/
ln -s /srv/apache-tomcat-7.0.40 /srv/apache-tomcat
rm -rf /srv/apache-tomcat/webapps/*

cat > /srv/apache-tomcat/bin/setenv.sh <<'EOF'
export JAVA_HOME=/srv/java
export JAVA_OPTS="-server -Xms512m -Xmx8192m  -XX:PermSize=64M -XX:MaxPermSize=512m"
export CATALINA_HOME=/srv/apache-tomcat
export CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CATALINA_HOME/lib:
export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$CATALINA_HOME/bin:
EOF

cp /srv/apache-tomcat/conf/server.xml{,.original}

groupadd -g 80 www
adduser -o --home /srv --uid 80 --gid 80 -c "Web Application" www

chown www:www -R /srv/*

su - www -c "/srv/apache-tomcat/bin/startup.sh"
			
			

或者運行下面腳本快速安裝

curl -sS https://raw.github.com/netkiller/shell/master/apache/tomcat/install.sh | bash
			

46.1.3. Java 8 + Tomcat 8

安裝Java 8

		
cd /usr/local/src/

tar zxf server-jre-8u20-linux-x64.gz 
mv jdk1.8.0_20 /srv/
ln -s /srv/jdk1.8.0_20 /srv/java

cat >> /etc/profile.d/java.sh <<'EOF'
export JAVA_HOME=/srv/java
export JAVA_OPTS="-server -Xms512m -Xmx8192m"
export CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CATALINA_HOME/lib:
export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$CATALINA_HOME/bin:
EOF		
		
		
[注意]注意

Java 8 取消了 PermSize 與 MaxPermSize 配置項"

		
cd /usr/local/src/
wget http://ftp.cuhk.edu.hk/pub/packages/apache.org/tomcat/tomcat-8/v8.0.12/bin/apache-tomcat-8.0.12.tar.gz
tar zxf apache-tomcat-8.0.12.tar.gz 

mv apache-tomcat-8.0.12 /srv/
ln -s /srv/apache-tomcat-8.0.12 /srv/apache-tomcat
rm -rf /srv/apache-tomcat/webapps/*
cp /srv/apache-tomcat/conf/server.xml{,.original}

cat > /srv/apache-tomcat/bin/setenv.sh <<'EOF'
export JAVA_HOME=/srv/java
export JAVA_OPTS="-server -Xms512m -Xmx8192m"
export CATALINA_HOME=/srv/apache-tomcat
export CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CATALINA_HOME/lib:/srv/IngrianJCE/lib/ext/IngrianNAE-5.1.1.jar
export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$CATALINA_HOME/bin:
EOF
		
		

啟動 Tomcat

groupadd -g 80 www
adduser -o --home /www --uid 80 --gid 80 -c "Web Application" www

chown www:www -R /srv/apache-tomcat-*

su - www -c "/srv/apache-tomcat/bin/startup.sh"		
		

46.1.3.1. systemctl 啟動腳本

curl -s https://raw.githubusercontent.com/oscm/shell/master/web/tomcat/systemctl.sh | bash
			

46.1.3.2. Session 共享

$ git clone https://github.com/chexagon/redis-session-manager.git
$ cd redis-session-manager/
$ mvn package
$ ls target/redis-session-manager-with-dependencies-2.1.1-SNAPSHOT.jar 
redis-session-manager-with-dependencies-2.1.1-SNAPSHOT.jar

$ cp target/redis-session-manager-with-dependencies-2.1.1-SNAPSHOT.jar /srv/apache-tomcat/apache-tomcat-8.5.11/lib/
			

如果Redis是 127.0.0.1 配置 conf/context.xml 加入下面一行,

			
<Manager className="com.crimsonhexagon.rsm.redisson.SingleServerSessionManager" />			
			
			

完整的配置

			
    <Manager className="com.crimsonhexagon.rsm.redisson.SingleServerSessionManager"
	    endpoint="localhost:6379"
	    sessionKeyPrefix="JSESSIONID::"
	    saveOnChange="false"
	    forceSaveAfterRequest="false"
	    dirtyOnMutation="false"
	    ignorePattern=".*\\.(ico|png|gif|jpg|jpeg|swf|css|js)$"
	    connectionPoolSize="100"
	    database="16"
	    password="yourpassword"
	    timeout="60000"
	    pingTimeout="1000"
	    retryAttempts="20"
	    retryInterval="1000"
    />
			
			

例 46.3. Example /srv/apache-tomcat/conf

				
cat context.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!-- The contents of this file will be loaded for each web application -->
<Context>

    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
    <Manager className="com.crimsonhexagon.rsm.redisson.SingleServerSessionManager"
	    endpoint="localhost:6379"
	    sessionKeyPrefix="JSESSIONID"
	    saveOnChange="false"
	    forceSaveAfterRequest="false"
	    dirtyOnMutation="false"
	    ignorePattern=".*\\.(ico|png|gif|jpg|jpeg|swf|css|js)$"
	    connectionPoolSize="100"
	    database="0"
	    password=""
	    timeout="60000"
	    pingTimeout="1000"
	    retryAttempts="20"
	    retryInterval="1000"
    />
</Context>
				
				
				

46.1.3.2.1. test session
				
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<!DOCTYPE html>  
<html>  
<head>  
<title>set session</title>  
</head>  
<body>
  <%= session.getId() %>
  <%  
    session.setAttribute("neo", "netkiller");   
  %>  
</body>  
</html>				
				
				
				
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<!DOCTYPE html>  
<html>  
<head>  
<title>get session</title>  
</head>  
<body>  
  <%= session.getId() %>  
  <br/>
  <br/>  
  <%=(String)session.getAttribute("neo")%>  
  
</body>  
</html>
				
				

46.1.4. 防火牆配置

iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
		

80 跳轉 8080 方案

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
		

取消跳轉

iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
		

查看規則

iptables -t nat -L
		

例 46.4. tomcat firewall

下面是完整的例子,僅供參考,複製到 /etc/sysconfig/iptables 檔案中,重啟iptables即可生效。

# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.4.7 on Mon Jul 22 15:58:35 2013
*nat
:PREROUTING ACCEPT [7:847]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-port 8080
COMMIT
# Completed on Mon Jul 22 15:58:35 2013
# Generated by iptables-save v1.4.7 on Mon Jul 22 15:58:35 2013
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [42303:3464247]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Mon Jul 22 15:58:35 2013
			

46.1.5. 同時運行多實例

創建工作目錄

mkdir /srv/apache-tomcat
		

每個連接埠一個目錄

tar zxvf apache-tomcat-7.0.x.tar.gz
mv  apache-tomcat-7.0.x /srv/apache-tomcat/8080

tar zxvf apache-tomcat-7.0.x.tar.gz
mv  apache-tomcat-7.0.x /srv/apache-tomcat/9090
		

修改 Server port="8006" 與 Connector port="9090"連接埠,不要出現重複。

		

<Server port="8006" shutdown="SHUTDOWN">


 <Connector port="9090" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

<!--
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
		
		

啟動tomcat然後觀察catalina.log日誌檔案,確認每個進程都正確啟動。

46.1.6. Testing file

創建測試檔案

vim webapps/ROOT/index.jsp
		
<%@ page contentType="text/html;charset=utf-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>helloworld!</title>
</head>

<body>
<h1>
<%="It works!"%>
</h1>
<%
out.println("<h3>Hello World!</h3>");
%>
<hr />
<%=new java.util.Date()%>
</body>
</html>
		
		

使用curl命令測試,測試結果類似下面結果。

		
$ curl http://192.168.6.9/index.jsp

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>helloworld!</title>
</head>

<body>
<h1>
It works!
</h1>
<h3>Hello World!</h3>

<hr />
Mon Jul 22 16:41:46 HKT 2013
</body>
</html>
		
		

46.1.7. mod_jk

mod_jk 安裝

tar zxvf tomcat-connectors-1.2.23-src.tar.gz
cd tomcat-connectors-1.2.23-src/native/
./configure --with-apxs=/usr/local/apache/bin/apxs
make
make install
chmod 755 /usr/local/apache/modules/mod_jk.so
		

httpd.conf 尾部加入

Include conf/mod_jk.conf
		

配置workers.properties

apache/conf/workers.properties
# Define 1 real worker using ajp13
worker.list=worker1
# Set properties for worker1 (ajp13)
worker.worker1.type=ajp13
worker.worker1.host=127.0.0.1
worker.worker1.port=8009
worker.worker1.lbfactor=1
worker.worker1.cachesize=128
worker.worker1.cache_timeout=600
worker.worker1.socket_keepalive=1
worker.worker1.reclycle_timeout=300
		

mod_jk.conf

apache/conf/mod_jk.conf
		
[chenjingfeng@d3010 Includes]$ cat mod_jk.conf
<IfModule mod_jk.c>
# Load mod_jk module
LoadModule jk_module            modules/mod_jk.so
# Where to find workers.properties
JkWorkersFile           /usr/local/apache/conf/workers.properties
# Where to put jk logs
JkLogFile               /usr/local/apache/logs/mod_jk.log
# Set the jk log level [debug/error/info]
JkLogLevel              error
# 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"
JkShmFile     /usr/local/apache2/logs/mod_jk.shm
# Send jsp,servlet for context * to worker named worker1
JkMount  /status/* worker1
JkMount  /*.jsp worker1
JkMount  /*.jsps worker1
JkMount  /*.do worker1
JkMount  /*Servlet worker1
JkMount  /jk/* worker1
</IfModule>
		
		

分別測試apache,tomcat

46.1.8. mod_proxy_ajp

包含虛擬主機配置檔案

# vi conf/httpd.conf
# Virtual hosts
Include conf/extra/httpd-vhosts.conf
		

虛擬主機中配置ProxyPass,ProxyPassReverse

# vi conf/extra/httpd-vhosts.conf
		
<VirtualHost *:80>
    ServerName netkiller.8800.org
    ProxyPass /images !
	ProxyPass /css !
	ProxyPass /js !
    ProxyPass /ajp ajp://localhost:8009/ajp
    ProxyPassReverse /ajp ajp://localhost:8009/ajp
</VirtualHost>
		
		

反向代理和均衡負載模組

		
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

ProxyPass /admin balancer://tomcatcluster/admin lbmethod=byrequests stickysession=JSESSIONID nofailover=Off timeout=5 maxattempts=3
ProxyPassReverse /admin balancer://tomcatcluster/admin

<Proxy balancer://tomcatcluster>
	BalancerMember ajp://localhost:8009 route=web1
	BalancerMember ajp://localhost:10009 smax=10 route=web2
	BalancerMember ajp://localhost:11009 route=web3
	BalancerMember ajp://localhost:12009 smax=10 route=web4
</Proxy>
		
		

46.1.9. RewriteEngine 連接 Tomcat

		
RewriteEngine On

RewriteRule ^/(.*) ajp://localhost:8009/ajp/$1 [P]
RewriteRule ^/(.*\.(jsp|do|sevlet)) ajp://localhost:8009/ajp/$1 [P]
		
		

46.1.10. SSL 雙向認證

首先我並不建議使用 tomcat 實現SSL雙向驗證,這個工作可以交給 Web 伺服器完成。但有些場景可能需要,可以參考下面例子。

伺服器端證書

keytool -genkey -v -alias serverKey -dname "CN=localhost" -keyalg RSA -keypass xxxxxx -keystore server.ks -storepass xxxxxx
		

客戶端證書

keytool -genkey -v -alias clientKey -dname "CN=SomeOne" -keyalg RSA -keypass xxxxxx -keystore client.p12 -storepass xxxxxx -storetype PKCS12		
keytool -export -alias clientKey -file clientKey.cer -keystore client.p12 -storepass xxxxxx -storetype PKCS12
		

導入客戶端證書

keytool -import -v -alias clientKey -file clientKey.cer -keystore server.ks -storepass xxxxxx		
		

如果希望在 Windows 瀏覽器中訪問,下導入證書方式,雙擊 client.p12 檔案,安裝提示導入

配置 Tomcat ,編輯 server.xml 檔案

		
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="1024" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="server.ks" keystorePass="xxxxxx"
truststoreFile="server.ks " truststorePass="xxxxxx" />