1. 为什么是 Tomcat 9 + Ubuntu 18.04 这个组合值得单独深挖
Apache Tomcat 9 是 Java Web 应用部署的基石级容器,而 Ubuntu 18.04(代号 Bionic Beaver)虽已结束标准支持周期,但在大量企业内网、遗留系统、教学实验环境及嵌入式边缘设备中,仍是真实在跑的主力发行版。我接手过的三个客户项目里,有两个明确要求“不能升级操作系统”,理由很实在:定制化监控脚本依赖特定内核模块、老旧硬件驱动只适配 4.15 内核、以及一套运行十年的财务中间件,其 JNI 调用链与 glibc 2.27 的符号版本强绑定——换新版 Ubuntu 意味着重写底层通信层。这不是技术守旧,而是成本与风险的理性权衡。
Tomcat 9 的关键价值在于它对 Servlet 4.0 和 JSP 2.3 规范的完整实现,尤其在 HTTP/2 支持、异步 Servlet 处理和 WebSocket 性能上,相比 Tomcat 8.5 有质的提升。但官方文档里一句轻描淡写的“requires Java 8 or later”背后,藏着 Ubuntu 18.04 的真实陷阱:系统默认的 OpenJDK 10 在 2018 年底就已 EOL,而 Tomcat 9.0.50+ 版本开始对 Java 11 的 TLS 1.3 握手流程做了深度优化。如果你直接apt install openjdk-11-jdk,会发现/usr/lib/jvm/java-11-openjdk-amd64/conf/security/java.security文件里jdk.tls.disabledAlgorithms配置项默认禁用了 TLS 1.0/1.1,这会导致某些老客户端(比如银行网点的 IE11 + ActiveX 插件)连接失败。这不是 Tomcat 的 bug,而是 Java 生态演进与现实兼容性之间的典型张力。
更隐蔽的问题在权限模型。Ubuntu 18.04 默认启用 systemd 的ProtectHome=true和PrivateTmp=true安全策略,而 Tomcat 9 的catalina.sh启动脚本在早期版本中会尝试写入/tmp/tomcat9-tmp目录。当 systemd 服务以非 root 用户运行时,这个路径会被隔离,导致应用启动时java.io.tmpdir指向一个空目录,进而引发 JSP 编译失败或 Session 持久化异常。这个问题在官方安装指南里完全没提,因为它的触发条件太具体:必须是 systemd 管理 + 非 root 用户 + Tomcat 9.0.30 以下版本。我第一次遇到时花了整整两天,用strace -e trace=mkdir,openat,write跟踪到第 17 层嵌套调用才定位到根源。
所以,这篇不是教你怎么点几下鼠标装好 Tomcat,而是带你拆解这个组合里所有被忽略的“毛细血管级”细节:Java 版本的精确匹配逻辑、systemd 服务单元文件的 7 个关键安全参数配置、setenv.sh中必须覆盖的 5 个 JVM 参数、以及如何用journalctl -u tomcat9 -f实时捕获比catalina.out更早的启动错误。这些不是可选项,而是让 Tomcat 9 在 Ubuntu 18.04 上真正“活下来”的生存手册。
2. Java 环境:从 apt 安装到生产级 JDK 的三重校验
在 Ubuntu 18.04 上部署 Tomcat 9,第一步永远不是下载 Tomcat,而是确认 Java 环境是否真的可靠。很多人卡在第一步,却以为是 Tomcat 配置问题。这里必须执行三重校验,缺一不可。
2.1 第一重校验:系统级 Java 版本与架构一致性
Ubuntu 18.04 的 APT 仓库里提供多个 OpenJDK 包,但它们的 ABI 兼容性并不完全一致。执行以下命令:
sudo apt update apt list --installed | grep openjdk java -version javac -version你可能会看到类似输出:
openjdk-11-jdk/bionic-updates,now 11.0.19+7-1~18.04.1 amd64 [installed] openjdk-8-jdk/bionic-updates,now 8u372-b07-0ubuntu1~18.04.1 amd64 [installed]注意:openjdk-11-jdk和openjdk-8-jdk可以共存,但java -version显示的版本取决于update-alternatives --config java的当前选择。Tomcat 9.0.x 要求 Java 8u201+ 或 Java 11.0.2+,这个“+”号很关键。Ubuntu 18.04 的openjdk-11-jdk11.0.19 版本是安全的,但如果你手动编译过旧版 OpenJDK 11,或者从第三方源安装了 11.0.1,就会触发 Tomcat 启动时的UnsupportedClassVersionError。验证方法是检查JAVA_HOME指向的jre/release文件:
$JAVA_HOME/jre/release正确输出应包含JAVA_VERSION="11.0.19"和OS_ARCH="amd64"。如果OS_ARCH="x86_64",说明你装的是 x86_64 架构的 JDK,而 Ubuntu 18.04 的内核是 amd64,虽然通常能运行,但在 JNI 调用时可能因符号解析失败导致 Segmentation Fault。这是很多 C++ 开发者转 Java 时踩的坑。
2.2 第二重校验:JVM 参数与 Tomcat 启动脚本的隐式耦合
Tomcat 9 的bin/catalina.sh脚本在启动时会读取bin/setenv.sh(如果存在),并从中加载 JVM 参数。但很多人不知道,catalina.sh本身也硬编码了部分参数。打开bin/catalina.sh,搜索JAVA_OPTS,你会看到:
# Ensure that any user defined CLASSPATH variables are not used on startup CLASSPATH= if [ -r "$CATALINA_BASE/bin/setenv.sh" ]; then . "$CATALINA_BASE/bin/setenv.sh" elif [ -r "$CATALINA_HOME/bin/setenv.sh" ]; then . "$CATALINA_HOME/bin/setenv.sh" fi关键点在于:setenv.sh是唯一被catalina.sh主动加载的自定义脚本,其他如catalina-env.sh或tomcat-env.sh都不会被识别。而setenv.sh必须是可执行的(chmod +x),且其中定义的变量必须用export声明。常见错误是写成:
# 错误:没有 export,变量不会传递给 JVM JAVA_OPTS="-Xms512m -Xmx1024m"正确写法是:
#!/bin/bash export JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom -Xms512m -Xmx1024m -XX:+UseG1GC" export CATALINA_PID="/var/run/tomcat9.pid"这里-Djava.security.egd=file:/dev/./urandom是 Ubuntu 18.04 的刚需。因为该系统默认的/dev/random在熵池不足时会阻塞,而 Tomcat 启动过程中的 SSL 密钥生成、Session ID 生成都依赖SecureRandom,阻塞会导致启动超时(默认 45 秒),最终systemctl start tomcat9报错 “Timed out waiting for process”。/dev/./urandom这个路径是故意加./的,因为 Java 的SecureRandom实现会检查路径是否为/dev/random或/dev/urandom,加./是绕过检查的公认技巧。
2.3 第三重校验:TLS 协议栈与遗留系统的握手兼容性
Tomcat 9 默认启用 TLS 1.2,但很多企业内部系统(如 Oracle E-Business Suite 12.1、SAP GUI 7.40)仍使用 TLS 1.0。直接在server.xml中添加<SSLHostConfig protocols="TLSv1.1,TLSv1.2">是无效的,因为 Java 11 的java.security文件默认禁用了 TLS 1.0/1.1。必须修改 JDK 的全局安全策略:
sudo nano $JAVA_HOME/conf/security/java.security找到jdk.tls.disabledAlgorithms行,将其改为:
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL注意:删除了TLSv1, TLSv1.1。改完后必须重启所有 Java 进程,包括systemctl restart tomcat9。验证方法是在 Tomcat 的webapps/ROOT/下放一个test.jsp,内容为:
<%= request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() %>然后用curl -v --tlsv1.0 https://localhost:8443/test.jsp测试。如果返回 200,说明 TLS 1.0 已启用;如果返回curl: (35) error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure,说明配置未生效。
提示:这个修改会降低整体安全性,仅建议在内网隔离环境中使用。生产外网环境必须强制 TLS 1.2+,并通过反向代理(如 Nginx)处理协议降级。
3. Tomcat 9 安装:从二进制包解压到 systemd 服务的 12 个关键动作
在 Ubuntu 18.04 上,apt install tomcat9看似最简单,但它安装的是 Ubuntu 维护的打包版本,其CATALINA_HOME和CATALINA_BASE路径、日志轮转策略、甚至webapps目录的 SELinux 上下文都与上游 Apache 官方二进制包不同。对于需要精确控制版本、补丁级别或自定义构建的场景,必须使用官方二进制包。以下是 12 个不可跳过的动作,每个都对应一个真实踩坑案例。
3.1 动作 1:下载与校验——为什么 SHA-512 是底线
访问 https://tomcat.apache.org/download.cgi,选择Binary Distributions → Core → tar.gz。截至 2024 年,最新稳定版是apache-tomcat-9.0.83.tar.gz。下载后,必须校验 SHA-512:
wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.83/bin/apache-tomcat-9.0.83.tar.gz wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.83/bin/apache-tomcat-9.0.83.tar.gz.sha512 sha512sum -c apache-tomcat-9.0.83.tar.gz.sha512为什么不用 MD5?因为 Ubuntu 18.04 的md5sum工具在处理大文件时有缓冲区溢出风险,曾导致我一次部署中校验通过但实际文件损坏,Tomcat 启动时报java.lang.NoClassDefFoundError: org/apache/catalina/startup/Bootstrap。SHA-512 是 Apache 官方提供的唯一校验方式,也是唯一能保证完整性的方案。
3.2 动作 2:解压与目录结构——CATALINA_HOME与CATALINA_BASE的物理分离
解压到/opt目录:
sudo tar -xzf apache-tomcat-9.0.83.tar.gz -C /opt/ sudo ln -s /opt/apache-tomcat-9.0.83 /opt/tomcat9关键点:/opt/tomcat9是CATALINA_HOME(Tomcat 的安装根目录),而CATALINA_BASE(实例工作目录)必须是另一个独立路径,比如/var/lib/tomcat9。这种分离是生产环境的黄金标准,原因有三:
- 升级安全:升级 Tomcat 时,只需替换
/opt/tomcat9的软链接,/var/lib/tomcat9下的conf、webapps、logs等目录完全不受影响。 - 多实例支持:可以轻松创建
/var/lib/tomcat9-staging和/var/lib/tomcat9-prod,共享同一个CATALINA_HOME。 - 权限隔离:
CATALINA_HOME可设为root:root且755,而CATALINA_BASE下的webapps可由部署用户写入,避免root运行 Web 应用的风险。
创建CATALINA_BASE:
sudo mkdir -p /var/lib/tomcat9/{conf,webapps,logs,temp,work} sudo cp -r /opt/tomcat9/conf/* /var/lib/tomcat9/conf/ sudo chown -R tomcat:tomcat /var/lib/tomcat9 sudo chmod -R 755 /var/lib/tomcat9注意:
cp -r不能用rsync -a,因为rsync -a会保留原始文件的root:root所有者,导致后续权限问题。
3.3 动作 3:创建专用用户——为什么tomcat用户不能是nologin
创建系统用户:
sudo groupadd --system tomcat sudo useradd --system --ingroup tomcat --home-dir /var/lib/tomcat9 --no-create-home --shell /bin/false tomcat这里--shell /bin/false是关键。很多教程用/usr/sbin/nologin,但在 Ubuntu 18.04 的某些最小化安装中,/usr/sbin/nologin可能不存在,导致systemd服务启动时User=tomcat参数解析失败,报错Failed to start tomcat9.service: Unit tomcat9.service has a bad unit file setting.。/bin/false是 POSIX 标准,绝对可靠。
3.4 动作 4:编写setenv.sh——5 个必须覆盖的 JVM 参数
在/var/lib/tomcat9/bin/下创建setenv.sh:
sudo mkdir -p /var/lib/tomcat9/bin sudo tee /var/lib/tomcat9/bin/setenv.sh << 'EOF' #!/bin/bash export JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64" export CATALINA_HOME="/opt/tomcat9" export CATALINA_BASE="/var/lib/tomcat9" export CATALINA_PID="/var/run/tomcat9.pid" export JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom -Xms512m -Xmx1024m -XX:+UseG1GC -Dfile.encoding=UTF-8" EOF sudo chmod +x /var/lib/tomcat9/bin/setenv.sh解释每个参数:
JAVA_HOME:必须指向jre目录的父目录,即.../java-11-openjdk-amd64,而不是.../jre。Tomcat 的catalina.sh会自动拼接jre子路径。CATALINA_PID:指定 PID 文件位置,这是systemd服务健康检查的基础。-Dfile.encoding=UTF-8:Ubuntu 18.04 的 locale 默认是C,不设此参数,JSP 中的中文会显示为?。
3.5 动作 5:systemd 服务单元文件——7 个安全参数的实战意义
创建/etc/systemd/system/tomcat9.service:
[Unit] Description=Apache Tomcat Web Application Container After=network.target [Service] Type=forking User=tomcat Group=tomcat Environment="JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64" Environment="CATALINA_HOME=/opt/tomcat9" Environment="CATALINA_BASE=/var/lib/tomcat9" Environment="CATALINA_PID=/var/run/tomcat9.pid" Environment="CATALINA_TMPDIR=/tmp/tomcat9-tmp" ExecStart=/opt/tomcat9/bin/startup.sh ExecStop=/opt/tomcat9/bin/shutdown.sh RestartSec=10 Restart=always # 关键安全参数 NoNewPrivileges=true ProtectHome=true ProtectSystem=full PrivateTmp=true ReadWritePaths=/var/lib/tomcat9 /var/log/tomcat9 /tmp/tomcat9-tmp MemoryLimit=2G CPUQuota=75% [Install] WantedBy=multi-user.target逐条解析安全参数:
NoNewPrivileges=true:阻止 Tomcat 进程通过setuid获取更高权限,即使 Web 应用存在漏洞也无法提权。ProtectHome=true:挂载/home、/root、/run/user为只读,防止攻击者读取用户 SSH 密钥。ProtectSystem=full:挂载/usr、/boot、/etc为只读,确保 Tomcat 无法篡改系统配置。PrivateTmp=true:为 Tomcat 创建独立的/tmp命名空间,避免与其他进程冲突。ReadWritePaths:显式声明哪些路径可写,这是Protect*参数的配套白名单。MemoryLimit=2G:硬限制内存,防止 OOM Killer 杀死其他关键进程。CPUQuota=75%:限制 CPU 使用率,避免 Tomcat 占满所有核心导致系统无响应。
注意:
ProtectSystem=full会挂载/etc为只读,因此server.xml的修改必须在CATALINA_BASE/conf/下进行,而非CATALINA_HOME/conf/。
3.6 动作 6:日志与临时目录——/tmp的双重陷阱
Ubuntu 18.04 的/tmp默认是tmpfs(内存文件系统),大小为内存的 50%。如果 Tomcat 的temp目录放在/tmp,当上传大文件或编译大量 JSP 时,会迅速耗尽内存。因此,CATALINA_TMPDIR必须指向磁盘路径:
sudo mkdir -p /var/tmp/tomcat9 sudo chown tomcat:tomcat /var/tmp/tomcat9 sudo chmod 1777 /var/tmp/tomcat9同时,在systemd服务文件中,ReadWritePaths必须包含/var/tmp/tomcat9,否则PrivateTmp=true会使其失效。
3.7 动作 7:防火墙与端口——ufw的精确放行
Ubuntu 18.04 默认安装ufw。Tomcat 默认监听 8080(HTTP)和 8005(Shutdown)。精确放行:
sudo ufw allow 8080/tcp sudo ufw allow from 192.168.1.0/24 to any port 8005 proto tcp第二条只允许内网管理网段访问 Shutdown 端口,这是关键安全措施。如果开放8005给公网,攻击者只需发送SHUTDOWN字符串即可关闭 Tomcat。
3.8 动作 8:SELinux 替代方案——AppArmor 的强制配置
Ubuntu 18.04 使用 AppArmor 而非 SELinux。必须为 Tomcat 创建配置文件/etc/apparmor.d/usr.sbin.tomcat9:
#include <tunables/global> /usr/sbin/tomcat9 { #include <abstractions/base> #include <abstractions/nameservice> #include <abstractions/user-tmp> /var/lib/tomcat9/** rwk, /var/log/tomcat9/** rwk, /var/tmp/tomcat9/** rwk, /proc/sys/kernel/osrelease r, /sys/devices/system/cpu/online r, }然后加载:
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.tomcat93.9 动作 9:启动与验证——journalctl的高级用法
启动服务:
sudo systemctl daemon-reload sudo systemctl enable tomcat9 sudo systemctl start tomcat9验证日志:
# 查看实时启动日志(比 catalina.out 更早) sudo journalctl -u tomcat9 -f # 查看启动过程中的所有错误(含内核级) sudo journalctl -u tomcat9 --since "2024-01-01" | grep -i "error\|fail\|exception" # 查看 Tomcat 进程的详细资源占用 sudo systemctl status tomcat9 -l3.10 动作 10:Web 应用部署——webapps目录的原子性更新
将 WAR 包部署到/var/lib/tomcat9/webapps/时,绝不能直接覆盖正在运行的 WAR。正确流程:
# 1. 停止应用(不是停止整个 Tomcat) curl -X GET "http://localhost:8080/manager/text/stop?path=/myapp" --user "admin:password" # 2. 删除旧应用 sudo rm -rf /var/lib/tomcat9/webapps/myapp* sudo rm -f /var/lib/tomcat9/webapps/myapp.war # 3. 复制新 WAR sudo cp myapp.war /var/lib/tomcat9/webapps/ # 4. 启动应用 curl -X GET "http://localhost:8080/manager/text/start?path=/myapp" --user "admin:password"3.11 动作 11:Manager 应用安全加固——tomcat-users.xml的最小权限
编辑/var/lib/tomcat9/conf/tomcat-users.xml:
<tomcat-users> <role rolename="manager-gui"/> <role rolename="manager-script"/> <user username="deployer" password="strong-password-here" roles="manager-script"/> </tomcat-users>禁止使用manager-gui角色,因为它允许通过 Web 界面上传 WAR,这是高危操作。manager-script仅允许通过 curl 或脚本调用,符合 CI/CD 自动化需求。
3.12 动作 12:健康检查端点——/manager/status的自动化集成
在 CI/CD 流水线中,部署后必须验证 Tomcat 是否真正就绪。使用curl检查 Manager 状态:
# 等待 Tomcat 启动完成 until curl -f http://localhost:8080/manager/status --user "deployer:strong-password-here" >/dev/null 2>&1; do echo "Waiting for Tomcat..." sleep 5 done echo "Tomcat is ready!"4. 故障排查:从systemctl status到strace的完整诊断链路
当systemctl start tomcat9失败时,90% 的人只会看systemctl status tomcat9,然后卡住。真正的诊断必须按顺序执行以下 5 步,每一步都对应一个典型故障场景。
4.1 第一步:systemctl status的隐藏信息
执行:
sudo systemctl status tomcat9 -l --no-pager关键看三行:
Active:行末尾的(code=exited, status=1/FAILURE)中的status=1是退出码,不是错误类型。Process:行显示ExecStart=/opt/tomcat9/bin/startup.sh的 PID,记下这个数字。Main PID:行显示主进程 PID,如果为0,说明startup.sh启动后立即退出。
此时,不要急着看journalctl,先做第二步。
4.2 第二步:journalctl的时间锚点分析
# 查看该次启动的全部日志(从启动命令发出到失败) sudo journalctl _PID=12345 -o short-precise # 查看 Tomcat 进程自身的 stdout/stderr(比上面更精准) sudo journalctl _SYSTEMD_UNIT=tomcat9.service -o short-precise --since "2024-01-01 10:00:00"-o short-precise输出带毫秒的时间戳,便于定位“启动后 2.3 秒发生什么”。常见模式:
- 如果日志在
INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument:之后立即中断,说明 JVM 启动失败,问题在JAVA_OPTS或JAVA_HOME。 - 如果日志停在
INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina],说明server.xml解析失败,通常是 XML 格式错误或端口被占用。
4.3 第三步:端口与文件锁排查——lsof与fuser的组合技
如果日志显示Address already in use: bind,执行:
# 查看哪个进程占用了 8080 sudo lsof -i :8080 # 查看哪个进程占用了 8005(Shutdown 端口) sudo lsof -i :8005 # 查看 /var/lib/tomcat9/work/Catalina/localhost/ROOT/ 下的 .jar 文件锁 sudo fuser -v /var/lib/tomcat9/work/Catalina/localhost/ROOT/*.jarfuser能显示哪个进程打开了.jar文件,这是lsof无法做到的。很多情况下,旧的 Tomcat 进程已僵死,但其打开的 JAR 文件句柄未释放,导致新实例无法加载。
4.4 第四步:strace深度跟踪——定位Permission denied的真实路径
当journalctl显示Permission denied但找不到具体文件时,用strace:
# 临时修改 systemd 服务,用 strace 启动 sudo systemctl edit tomcat9在编辑器中输入:
[Service] ExecStart= ExecStart=/usr/bin/strace -f -e trace=openat,open,write,connect -o /tmp/tomcat-strace.log /opt/tomcat9/bin/startup.sh然后重启:
sudo systemctl daemon-reload sudo systemctl start tomcat9查看/tmp/tomcat-strace.log,搜索EACCES(Permission denied):
[pid 12345] openat(AT_FDCWD, "/var/lib/tomcat9/conf/server.xml", O_RDONLY) = -1 EACCES (Permission denied)这说明tomcat用户对server.xml没有读权限,ls -l /var/lib/tomcat9/conf/server.xml就会显示root:root所有者。
4.5 第五步:systemd-analyze的启动瓶颈分析
如果 Tomcat 启动慢(超过 30 秒),用:
sudo systemd-analyze blame sudo systemd-analyze critical-chain tomcat9.service输出类似:
The time when unit became active or started is printed after the "@" character. The time the unit took to start is printed after the "+" character. 10.234s tomcat9.service └─6.789s network-online.target └─6.788s systemd-networkd-wait-online.service这说明 Tomcat 等待网络就绪花了 6.788 秒。解决方案是在tomcat9.service的[Unit]段添加:
Wants=network.target After=network.target去掉network-online.target,因为后者等待 DHCP 完成,而network.target只需网络接口 UP 即可。
5. 生产就绪:性能调优、日志轮转与安全加固的 7 个硬核实践
安装完成只是起点,让 Tomcat 9 在 Ubuntu 18.04 上稳定运行一年以上,需要这 7 个经过线上验证的实践。
5.1 JVM GC 调优:G1GC 的 3 个关键阈值
Tomcat 9 默认使用 Parallel GC,但在 Ubuntu 18.04 的 4GB 内存服务器上,Parallel GC 会导致 Full GC 频繁。改用 G1GC:
export JAVA_OPTS="-Xms1g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=2M -XX:G1ReservePercent=15"MaxGCPauseMillis=200:目标 GC 停顿时间 200ms,G1 会动态调整堆区域大小来满足。G1HeapRegionSize=2M:Ubuntu 18.04 的默认页面大小是 4KB,2MB 区域大小能平衡碎片与吞吐。G1ReservePercent=15:预留 15% 堆空间,防止并发标记时内存不足触发 Full GC。
验证是否生效:
sudo jstat -gc $(pgrep -f "org.apache.catalina.startup.Bootstrap") 1s输出中G1-YC(Young GC)和G1-Full(Full GC)列应极少出现。
5.2 日志轮转:logrotate的 Tomcat 专用配置
创建/etc/logrotate.d/tomcat9:
/var/log/tomcat9/*.log { daily missingok rotate 30 compress delaycompress notifempty create 644 tomcat tomcat sharedscripts postrotate if [ -f /var/run/tomcat9.pid ]; then kill -USR1 `cat /var/run/tomcat9.pid` fi endscript }关键点:kill -USR1向 Tomcat 发送 USR1 信号,触发java.util.logging的LogManager重新加载配置,实现无缝日志切换。create 644 tomcat tomcat确保新日志文件权限正确。
5.3 连接池调优:server.xml中Connector的 5 个致命参数
编辑/var/lib/tomcat9/conf/server.xml,找到Connector标签:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxThreads="200" minSpareThreads="25" maxSpareThreads="75" acceptCount="100" disableUploadTimeout="true" compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml,text/plain,application/javascript,application/json" />maxThreads="200":Ubuntu 18.04 的默认ulimit -n是 1024,200 线程足够,再高会导致Too many open files。acceptCount="100":当所有线程忙时,最多排队 100 个请求,超过则拒绝。这是防 DDOS 的第一道防线。compressionMinSize="2048":只压缩大于 2KB 的响应,避免小响应的 CPU 开销。
5.4 安全头加固:web.xml的filter配置
在/var/lib/tomcat9/conf/web.xml的<web-app>标签下添加:
<filter> <filter-name>httpHeaderSecurity</filter-name> <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class> <init-param> <param-name>hstsMaxAgeSeconds</param-name> <param-value>31536000</param-value> </init-param> <init-param> <param-name>blockContentTypeSniffing</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>httpHeaderSecurity</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>这会自动添加Strict-Transport-Security、X-Content-Type-Options: nosniff等头,无需修改应用代码。
5.5 会话持久化:context.xml的集群配置
如果有多台 Tomcat,编辑/var/lib/tomcat9/conf/context.xml:
<Context> <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> </Context>DeltaManager采用增量同步,比BackupManager更适合 Ubuntu 18.04 的千兆内网环境。
5.6 内存泄漏防护:catalina.sh的JAVA_OPTS增强
在setenv.sh中添加:
export JAVA_OPTS