Tomcat 服务器配置详解

Server Configuration

概述

Tomcat的server.xml是核心配置文件,定义了服务器的整体架构和行为。本文将深入解析server.xml的各个组件配置,包括Service、Engine、Host、Context等关键元素的详细配置方法。

1. server.xml文件结构

1.1 配置文件层次结构

<Server>                    <!-- 服务器根元素 -->
  <GlobalNamingResources>   <!-- 全局JNDI资源 -->
  </GlobalNamingResources>

  <Service>                 <!-- 服务定义 -->
    <Connector>             <!-- 连接器 -->
    </Connector>

    <Engine>                <!-- 引擎 -->
      <Realm>               <!-- 认证领域 -->
      </Realm>

      <Host>                <!-- 虚拟主机 -->
        <Context>           <!-- 上下文 -->
        </Context>
        <Valve>             <!-- 阀门 -->
        </Valve>
      </Host>
    </Engine>
  </Service>
</Server>

1.2 配置文件备份策略

#!/bin/bash
# backup-server-config.sh

CATALINA_HOME="/opt/tomcat9"
BACKUP_DIR="/var/backups/tomcat"
DATE=$(date +%Y%m%d_%H%M%S)

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份server.xml和相关配置
cp $CATALINA_HOME/conf/server.xml $BACKUP_DIR/server.xml.$DATE
cp $CATALINA_HOME/conf/web.xml $BACKUP_DIR/web.xml.$DATE
cp $CATALINA_HOME/conf/context.xml $BACKUP_DIR/context.xml.$DATE
cp $CATALINA_HOME/conf/tomcat-users.xml $BACKUP_DIR/tomcat-users.xml.$DATE

echo "配置文件已备份到: $BACKUP_DIR"

# 保留最近10个备份
find $BACKUP_DIR -name "*.xml.*" -type f | sort | head -n -40 | xargs rm -f

2. Server元素配置

2.1 基础Server配置

<Server port="8005" 
        shutdown="SHUTDOWN"
        address="127.0.0.1">

  <!-- 服务器监听器 -->
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" 
            SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <!-- 全局JNDI资源定义 -->
  <GlobalNamingResources>
    <!-- 用户数据库 -->
    <Resource name="UserDatabase" 
              auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database for authentication"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />

    <!-- 数据库连接池 -->
    <Resource name="jdbc/MyDB" 
              auth="Container"
              type="javax.sql.DataSource"
              driverClassName="com.mysql.cj.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/myapp?useSSL=false&amp;serverTimezone=Asia/Shanghai"
              username="dbuser"
              password="dbpass"
              maxTotal="20"
              maxIdle="10"
              maxWaitMillis="10000"
              validationQuery="SELECT 1"
              testOnBorrow="true"
              testWhileIdle="true"
              timeBetweenEvictionRunsMillis="30000"
              minEvictableIdleTimeMillis="60000" />

    <!-- 邮件会话 -->
    <Resource name="mail/Session" 
              auth="Container"
              type="javax.mail.Session"
              mail.smtp.host="smtp.example.com"
              mail.smtp.port="587"
              mail.smtp.auth="true"
              mail.smtp.starttls.enable="true"
              username="noreply@example.com"
              password="mailpass" />
  </GlobalNamingResources>
</Server>

2.2 高级Server配置

<Server port="8005" 
        shutdown="SECURE_SHUTDOWN_STRING"
        address="127.0.0.1"
        className="org.apache.catalina.core.StandardServer">

  <!-- 自定义服务器监听器 -->
  <Listener className="com.example.CustomServerLifecycleListener" />

  <!-- JMX远程监控配置 -->
  <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
            rmiRegistryPortPlatform="9999"
            rmiServerPortPlatform="9998"
            useLocalPorts="false" />

  <!-- 性能监控监听器 -->
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" 
            logArgs="true" 
            logEnv="true" 
            logProps="true" />
</Server>

3. Service元素配置

3.1 基础Service配置

<Service name="Catalina">

  <!-- HTTP连接器 -->
  <Connector port="8080" 
             protocol="HTTP/1.1"
             connectionTimeout="20000"
             redirectPort="8443"
             maxThreads="200"
             minSpareThreads="10"
             maxSpareThreads="75"
             enableLookups="false"
             compression="on"
             compressionMinSize="2048"
             compressibleMimeType="text/html,text/xml,text/css,application/javascript,application/json"
             URIEncoding="UTF-8" />

  <!-- HTTPS连接器 -->
  <Connector port="8443" 
             protocol="org.apache.coyote.http11.Http11NioProtocol"
             maxThreads="150" 
             SSLEnabled="true"
             compression="on">
    <SSLHostConfig>
      <Certificate certificateKeystoreFile="conf/keystore.jks"
                   certificateKeystorePassword="changeit"
                   type="RSA" />
    </SSLHostConfig>
  </Connector>

  <!-- AJP连接器(用于与Apache集成) -->
  <Connector port="8009" 
             protocol="AJP/1.3" 
             redirectPort="8443"
             secretRequired="false"
             address="0.0.0.0" />

  <!-- 引擎配置 -->
  <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
    <!-- Engine内容在下一节详述 -->
  </Engine>
</Service>

3.2 多Service配置

<!-- 主服务 - 生产应用 -->
<Service name="Production">
  <Connector port="8080" protocol="HTTP/1.1" />
  <Engine name="ProductionEngine" defaultHost="app.example.com">
    <Host name="app.example.com" appBase="webapps">
      <!-- 生产应用配置 -->
    </Host>
  </Engine>
</Service>

<!-- 管理服务 - 管理界面 -->
<Service name="Management">
  <Connector port="8081" protocol="HTTP/1.1" />
  <Engine name="ManagementEngine" defaultHost="admin.example.com">
    <Host name="admin.example.com" appBase="admin-webapps">
      <!-- 管理应用配置 -->
    </Host>
  </Engine>
</Service>

4. Engine元素配置

4.1 基础Engine配置

<Engine name="Catalina" 
        defaultHost="localhost" 
        jvmRoute="node1">

  <!-- 认证领域配置 -->
  <Realm className="org.apache.catalina.realm.LockOutRealm">
    <!-- 数据库认证领域 -->
    <Realm className="org.apache.catalina.realm.DataSourceRealm"
           dataSourceName="jdbc/AuthDB"
           userTable="users"
           userNameCol="username"
           userCredCol="password"
           userRoleTable="user_roles"
           roleNameCol="role_name" />
  </Realm>

  <!-- 集群配置(如果启用集群) -->
  <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
    <!-- 集群配置详见集群章节 -->
  </Cluster>

  <!-- 虚拟主机配置 -->
  <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
    <!-- Host配置在下一节详述 -->
  </Host>
</Engine>

4.2 多域名Engine配置

<Engine name="Catalina" defaultHost="www.example.com">

  <!-- 组合认证领域 -->
  <Realm className="org.apache.catalina.realm.CombinedRealm">
    <!-- LDAP认证 -->
    <Realm className="org.apache.catalina.realm.JNDIRealm"
           connectionURL="ldap://ldap.example.com:389"
           userPattern="uid={0},ou=people,dc=example,dc=com"
           roleBase="ou=groups,dc=example,dc=com"
           roleName="cn"
           roleSearch="(member={0})" />

    <!-- 数据库认证(备用) -->
    <Realm className="org.apache.catalina.realm.DataSourceRealm"
           dataSourceName="jdbc/UserDB"
           userTable="users"
           userNameCol="username"
           userCredCol="password"
           userRoleTable="user_roles"
           roleNameCol="role_name" />
  </Realm>

  <!-- 主域名 -->
  <Host name="www.example.com" appBase="webapps" />

  <!-- API域名 -->
  <Host name="api.example.com" appBase="api-webapps" />

  <!-- 静态资源域名 -->
  <Host name="static.example.com" appBase="static-webapps" />
</Engine>

5. Host元素配置

5.1 基础Host配置

<Host name="localhost" 
      appBase="webapps"
      unpackWARs="true" 
      autoDeploy="true"
      deployOnStartup="true"
      createDirs="true">

  <!-- 访问日志阀门 -->
  <Valve className="org.apache.catalina.valves.AccessLogValve" 
         directory="logs"
         prefix="localhost_access_log" 
         suffix=".txt"
         pattern="%h %l %u %t &quot;%r&quot; %s %b %D &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot;"
         rotatable="true"
         renameOnRotate="true"
         maxDays="30" />

  <!-- 错误报告阀门 -->
  <Valve className="org.apache.catalina.valves.ErrorReportValve"
         showReport="false"
         showServerInfo="false" />

  <!-- 默认上下文 -->
  <Context path="" docBase="ROOT" reloadable="false">
    <!-- 资源链接 -->
    <ResourceLink name="jdbc/MyDB"
                  global="jdbc/MyDB"
                  type="javax.sql.DataSource" />
  </Context>
</Host>

5.2 生产环境Host配置

<Host name="app.example.com" 
      appBase="webapps"
      unpackWARs="false" 
      autoDeploy="false"
      deployOnStartup="true">

  <!-- 域名别名 -->
  <Alias>example.com</Alias>
  <Alias>www.app.example.com</Alias>

  <!-- 高级访问日志 -->
  <Valve className="org.apache.catalina.valves.AccessLogValve" 
         directory="logs"
         prefix="app_access_log" 
         suffix=".txt"
         pattern='%h %l %u %t "%r" %s %b %D "%{Referer}i" "%{User-Agent}i" %{X-Forwarded-For}i'
         rotatable="true"
         buffered="false"
         requestAttributesEnabled="true" />

  <!-- 远程IP阀门(用于负载均衡环境) -->
  <Valve className="org.apache.catalina.valves.RemoteIpValve"
         remoteIpHeader="X-Forwarded-For"
         remoteIpProxiesHeader="X-Forwarded-By"
         trustedProxies="192\.168\.1\..*|127\.0\.0\.1" />

  <!-- 限流阀门 -->
  <Valve className="org.apache.catalina.valves.SemaphoreValve"
         concurrency="100"
         fairness="true"
         block="true" />

  <!-- 应用上下文 -->
  <Context path="" 
           docBase="/opt/apps/myapp.war" 
           reloadable="false"
           crossContext="false"
           swallowOutput="true">

    <!-- 数据源配置 -->
    <Resource name="jdbc/AppDB" 
              auth="Container"
              type="javax.sql.DataSource"
              factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
              driverClassName="com.mysql.cj.jdbc.Driver"
              url="jdbc:mysql://db.example.com:3306/appdb"
              username="appuser"
              password="encrypted:abcd1234"
              maxActive="100"
              maxIdle="30"
              maxWait="10000"
              initialSize="10"
              validationQuery="SELECT 1"
              testOnBorrow="true"
              testOnReturn="false"
              testWhileIdle="true"
              timeBetweenEvictionRunsMillis="30000"
              numTestsPerEvictionRun="3"
              minEvictableIdleTimeMillis="60000"
              removeAbandoned="true"
              removeAbandonedTimeout="60"
              logAbandoned="true"
              jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer" />

    <!-- 环境变量 -->
    <Environment name="app.env" 
                 value="production" 
                 type="java.lang.String" />
    <Environment name="app.debug" 
                 value="false" 
                 type="java.lang.Boolean" />
  </Context>
</Host>

6. Valve配置详解

6.1 访问控制Valve

<!-- IP访问控制 -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
       allow="192\.168\.1\..*|127\.0\.0\.1"
       deny=".*" />

<!-- 主机名访问控制 -->
<Valve className="org.apache.catalina.valves.RemoteHostValve"
       allow=".*\.example\.com|localhost"
       deny=".*\.malicious\.com" />

<!-- 时间访问控制 -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
       pattern="%h %l %u %t &quot;%r&quot; %s %b"
       condition="!skipLogging" />

6.2 自定义Valve

// CustomSecurityValve.java
package com.example.valve;

import org.apache.catalina.valves.ValveBase;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;

import javax.servlet.ServletException;
import java.io.IOException;

public class CustomSecurityValve extends ValveBase {

    private String allowedUserAgents = ".*";
    private String blockedUserAgents = "";
    private int maxRequestsPerMinute = 100;

    @Override
    public void invoke(Request request, Response response) 
            throws IOException, ServletException {

        // 检查User-Agent
        String userAgent = request.getHeader("User-Agent");
        if (userAgent != null && !userAgent.matches(allowedUserAgents)) {
            response.sendError(403, "Forbidden User Agent");
            return;
        }

        if (userAgent != null && !blockedUserAgents.isEmpty() 
            && userAgent.matches(blockedUserAgents)) {
            response.sendError(403, "Blocked User Agent");
            return;
        }

        // 限流检查
        String clientIP = request.getRemoteAddr();
        if (isRateLimited(clientIP)) {
            response.sendError(429, "Too Many Requests");
            return;
        }

        // 调用下一个Valve
        getNext().invoke(request, response);
    }

    private boolean isRateLimited(String clientIP) {
        // 实现限流逻辑
        // 可以使用Redis或内存缓存来跟踪请求频率
        return false;
    }

    // Getter和Setter方法
    public void setAllowedUserAgents(String allowedUserAgents) {
        this.allowedUserAgents = allowedUserAgents;
    }

    public void setBlockedUserAgents(String blockedUserAgents) {
        this.blockedUserAgents = blockedUserAgents;
    }

    public void setMaxRequestsPerMinute(int maxRequestsPerMinute) {
        this.maxRequestsPerMinute = maxRequestsPerMinute;
    }
}

配置自定义Valve:

<Valve className="com.example.valve.CustomSecurityValve"
       allowedUserAgents="Mozilla.*|Chrome.*"
       blockedUserAgents=".*bot.*|.*crawler.*"
       maxRequestsPerMinute="60" />

7. Context配置详解

7.1 应用Context配置

<Context path="/myapp" 
         docBase="/opt/apps/myapp"
         reloadable="false"
         crossContext="false"
         privileged="false"
         allowLinking="false"
         swallowOutput="true"
         sessionCookieName="JSESSIONID"
         sessionCookiePath="/"
         sessionCookieMaxAge="-1"
         sessionTimeout="30">

  <!-- 应用参数 -->
  <Parameter name="app.name" value="MyApplication" />
  <Parameter name="app.version" value="1.0.0" />

  <!-- 环境变量 -->
  <Environment name="jdbc/maxConnections" 
               value="100" 
               type="java.lang.Integer" />

  <!-- 资源配置 -->
  <Resource name="jdbc/AppDB" 
            auth="Container"
            type="javax.sql.DataSource"
            driverClassName="com.mysql.cj.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/appdb"
            username="appuser"
            password="apppass"
            maxTotal="20"
            maxIdle="10"
            maxWaitMillis="10000" />

  <!-- 事务配置 -->
  <Transaction factory="org.apache.catalina.core.DefaultTransactionFactory" />

  <!-- Web资源集合 -->
  <Resources>
    <PreResources className="org.apache.catalina.webresources.DirResourceSet"
                  webAppMount="/WEB-INF/lib"
                  base="/opt/shared-libs" />
  </Resources>

  <!-- 管理器配置 -->
  <Manager className="org.apache.catalina.session.PersistentManager"
           saveOnRestart="true"
           maxActiveSession="-1"
           minIdleSwap="10"
           maxIdleSwap="20"
           maxIdleBackup="5">
    <Store className="org.apache.catalina.session.FileStore"
           directory="/opt/tomcat/sessions" />
  </Manager>
</Context>

7.2 安全Context配置

<Context path="/secure-app" 
         docBase="/opt/secure-apps/secure-app"
         reloadable="false"
         privileged="true"
         allowLinking="false">

  <!-- 安全约束 -->
  <Realm className="org.apache.catalina.realm.DataSourceRealm"
         dataSourceName="jdbc/AuthDB"
         userTable="users"
         userNameCol="username"
         userCredCol="password"
         userRoleTable="user_roles"
         roleNameCol="role_name"
         digest="SHA-256" />

  <!-- 访问控制 -->
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="192\.168\.1\..*" />

  <!-- HTTPS重定向 -->
  <Valve className="org.apache.catalina.valves.SSLValve" />

  <!-- 安全头 -->
  <Valve className="org.apache.catalina.valves.HttpHeaderSecurityFilter"
         hstsMaxAgeSeconds="31536000"
         hstsIncludeSubdomains="true"
         antiClickJackingEnabled="true"
         antiClickJackingOption="SAMEORIGIN"
         blockContentTypeSniffingEnabled="true" />
</Context>

8. 全局配置管理

8.1 配置模板化

#!/bin/bash
# generate-server-xml.sh

ENV=${1:-development}
TEMPLATE_DIR="/opt/tomcat/config-templates"
OUTPUT_FILE="/opt/tomcat/conf/server.xml"

case $ENV in
  "development")
    HTTP_PORT=8080
    HTTPS_PORT=8443
    AJP_PORT=8009
    DEBUG_ENABLED=true
    ;;
  "staging")
    HTTP_PORT=8080
    HTTPS_PORT=8443
    AJP_PORT=8009
    DEBUG_ENABLED=false
    ;;
  "production")
    HTTP_PORT=80
    HTTPS_PORT=443
    AJP_PORT=8009
    DEBUG_ENABLED=false
    ;;
esac

# 使用envsubst替换变量
envsubst < "$TEMPLATE_DIR/server.xml.template" > "$OUTPUT_FILE"

echo "生成配置文件: $OUTPUT_FILE (环境: $ENV)"

8.2 配置验证脚本

#!/bin/bash
# validate-config.sh

CATALINA_HOME="/opt/tomcat9"
CONFIG_FILE="$CATALINA_HOME/conf/server.xml"

echo "=== Tomcat配置验证 ==="

# 检查XML语法
if xmllint --noout "$CONFIG_FILE" 2>/dev/null; then
    echo "✓ XML语法正确"
else
    echo "✗ XML语法错误"
    xmllint "$CONFIG_FILE"
    exit 1
fi

# 检查Tomcat配置
if $CATALINA_HOME/bin/catalina.sh configtest; then
    echo "✓ Tomcat配置正确"
else
    echo "✗ Tomcat配置错误"
    exit 1
fi

# 检查端口占用
PORTS=("8080" "8443" "8005" "8009")
for port in "${PORTS[@]}"; do
    if netstat -tuln | grep ":$port " > /dev/null; then
        echo "⚠ 端口 $port 已被占用"
    else
        echo "✓ 端口 $port 可用"
    fi
done

# 检查Java版本兼容性
JAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2)
echo "✓ Java版本: $JAVA_VERSION"

# 检查内存设置
if [ -f "$CATALINA_HOME/bin/setenv.sh" ]; then
    echo "✓ 找到JVM参数配置文件"
    grep -E "Xms|Xmx" "$CATALINA_HOME/bin/setenv.sh"
else
    echo "⚠ 未找到JVM参数配置文件"
fi

echo "=== 配置验证完成 ==="

9. 动态配置管理

9.1 JMX配置管理

// ConfigurationManager.java
package com.example.tomcat.management;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;

public class ConfigurationManager {

    private MBeanServer mbs;

    public ConfigurationManager() {
        this.mbs = ManagementFactory.getPlatformMBeanServer();
    }

    public void updateConnectorMaxThreads(String serviceName, 
                                         String connectorPort, 
                                         int maxThreads) throws Exception {

        ObjectName connectorName = new ObjectName(
            "Catalina:type=Connector,service=" + serviceName + ",port=" + connectorPort
        );

        mbs.setAttribute(connectorName, 
                        new javax.management.Attribute("maxThreads", maxThreads));

        System.out.println("连接器最大线程数已更新为: " + maxThreads);
    }

    public void updateDataSourceSettings(String contextPath, 
                                       String resourceName,
                                       int maxTotal) throws Exception {

        ObjectName resourceName = new ObjectName(
            "Catalina:type=Resource,resourcetype=Global,class=javax.sql.DataSource,name=\"" 
            + resourceName + "\""
        );

        mbs.setAttribute(resourceName, 
                        new javax.management.Attribute("maxTotal", maxTotal));

        System.out.println("数据源最大连接数已更新为: " + maxTotal);
    }

    public String getServerInfo() throws Exception {
        ObjectName serverName = new ObjectName("Catalina:type=Server");
        return (String) mbs.getAttribute(serverName, "serverInfo");
    }
}

9.2 配置热重载

#!/bin/bash
# reload-config.sh

CATALINA_HOME="/opt/tomcat9"
CONFIG_FILE="$CATALINA_HOME/conf/server.xml"
BACKUP_FILE="$CONFIG_FILE.backup.$(date +%Y%m%d_%H%M%S)"

# 备份当前配置
cp "$CONFIG_FILE" "$BACKUP_FILE"

# 验证新配置
if ! $CATALINA_HOME/bin/catalina.sh configtest; then
    echo "配置验证失败,恢复备份"
    cp "$BACKUP_FILE" "$CONFIG_FILE"
    exit 1
fi

# 发送信号重新加载配置(需要自定义监听器支持)
TOMCAT_PID=$(ps aux | grep catalina | grep -v grep | awk '{print $2}')
if [ ! -z "$TOMCAT_PID" ]; then
    kill -USR1 $TOMCAT_PID
    echo "已发送配置重载信号到进程: $TOMCAT_PID"
else
    echo "Tomcat进程未找到,需要重启服务"
    systemctl restart tomcat
fi

小结

通过本文学习,你应该掌握:

  1. server.xml文件的完整结构和层次关系
  2. Server、Service、Engine、Host、Context各元素的详细配置
  3. Valve组件的使用和自定义开发
  4. JNDI资源的配置和管理
  5. 安全配置和访问控制
  6. 配置文件的模板化和验证
  7. 动态配置管理和热重载技术

下一篇文章将详细介绍Tomcat连接器的配置与优化。

powered by Gitbook© 2025 编外计划 | 最后修改: 2025-08-29 15:40:15

results matching ""

    No results matching ""