简介:本资源为Apache官方发布的Linux平台Tomcat 8.5.35核心发行版,面向Java Web开发者、运维工程师及高校教学实践者,用于快速搭建轻量级Servlet容器环境,支撑Java应用开发、测试与部署。压缩包共645个文件,涵盖236个HTML文档(含官方帮助与API说明)、100个class字节码、75个Java源码(便于调试理解)、59个JSP示例、31个JAR依赖库、16个XML配置模板(如server.xml、web.xml),以及startup.sh/shutdown.sh等9个Linux启动脚本,完整呈现Tomcat标准目录结构与运行机制。资源大小9.2MB,精简高效,开箱即用。目前已有555人学习下载,读者可直接获取包含bin/conf/lib/webapps/logs/work等全部标准子目录的可执行环境,掌握Catalina容器、Jasper引擎与Coyote连接器的协同原理,并基于预置配置快速开展HTTPS启用、访问控制配置及WAR包热部署等典型运维操作。
1. Tomcat 8.5.35 这个“老而稳”的 Linux 发行包,到底值不值得现在还手动部署?
如果你在某高校实验室维护一套老旧但仍在跑教学系统的 Java Web 平台,或者在某公司内部支撑着一个没上云、没容器化、却要持续三年不宕机的资产管理系统——那你大概率会遇到tomcat8-8.5.35.tar.gz这个文件名。它不是最新版(Tomcat 10+ 已支持 Jakarta EE 9+),也不是 LTS 长期支持版(Apache 官方对 8.5.x 的维护早在 2021 年底就正式终止),但它却是 Linux 环境下被实际复用最多、文档最全、排障路径最清晰的 Tomcat 小版本之一。尤其在国产化信创适配初期,很多中间件白名单只认到 8.5.35;某些遗留 Spring Boot 1.5.x 应用打包成 WAR 后,在 8.5.35 上零修改就能跑通,换 9.x 反而因 Servlet API 版本跳变报NoClassDefFoundError。这不是技术怀旧,而是真实存在的兼容性锚点:当你需要一个不依赖 systemd 服务封装、不强求 OpenJDK 11+、能直接解压即启、且日志/权限/端口配置全部可控的轻量级 Servlet 容器时,8.5.35 仍是 Linux 下最可靠的“手操型”选择。本文不讲 Docker 部署,不推一键脚本,只聚焦于:如何在一台干净的 CentOS 7 / Ubuntu 20.04 等主流 Linux 发行版上,从零完成tomcat8-8.5.35.tar.gz的安全、可维护、可监控的手动部署,并把那些藏在conf/server.xml注释里、被运维手册跳过的细节,一条条掰开揉碎。
2. 下载、校验与解压:别让第一步就埋下玄学故障
2.1 从官方归档库精准定位并下载 tar.gz 包
Tomcat 8.5.x 系列已归档至 Apache 的 Archive Repository 。注意:绝不能从第三方镜像站或百度网盘下载该版本——部分非官方源会悄悄替换bin/catalina.sh插入监控脚本,或修改lib/tomcat-juli.jar埋点。必须使用官方 SHA512 校验码验证完整性。
# 创建专用目录,避免污染 /opt 或 /usr/local mkdir -p /opt/tomcat8 && cd /opt/tomcat8 # 使用 curl 下载(wget 同理),注意 URL 中的 'bin' 路径,不是 'src' curl -O https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.35/bin/apache-tomcat-8.5.35.tar.gz curl -O https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.35/bin/apache-tomcat-8.5.35.tar.gz.sha512提示:
v8.5.35/bin/是归档路径,不是版本号拼写错误。Tomcat 官方归档结构固定为v{version}/bin/,下载前务必核对 URL 是否含/bin/,否则会 404。
2.2 用 sha512sum 严格校验,拒绝“差不多就行”
# 检查校验文件内容是否匹配官方发布页(需人工比对) cat apache-tomcat-8.5.35.tar.gz.sha512 # 输出应为:a1b2c3d4...e5f6 apache-tomcat-8.5.35.tar.gz (共 128 位十六进制) # 执行校验(注意空格和文件名顺序!) sha512sum -c apache-tomcat-8.5.35.tar.gz.sha512 # ✅ 正确输出:apache-tomcat-8.5.35.tar.gz: OK # ❌ 若报错 "NOPE" 或 "FAILED",立即删除重下,切勿跳过逻辑说明:sha512sum -c会读取.sha512文件中指定的哈希值,并对同名.tar.gz文件计算哈希后比对。参数-c是关键,缺了它只是打印哈希值,无法校验。
2.3 解压并建立规范目录结构:为什么不用 root 解压?
# 必须用非 root 用户解压(如 tomcat 用户),禁止 sudo tar -xzf tar -xzf apache-tomcat-8.5.35.tar.gz # 重命名解压目录,去掉版本号便于后续升级(这是血泪经验) mv apache-tomcat-8.5.35 tomcat8-prod # 设置属主:tomcat 用户(需提前创建)拥有全部文件,root 仅保留组权限 useradd -r -s /sbin/nologin tomcat chown -R tomcat:tomcat tomcat8-prod chmod -R u+rwx,g+rX,o-rwx tomcat8-prod参数说明:
-r:创建系统用户(UID < 1000),无家目录、无 shell;u+rwx,g+rX:用户读写执行,组读执行(X 表示仅对目录和已有执行位的文件加执行);o-rwx:其他用户彻底无权限——这是生产环境硬性要求,防止 WAR 包内恶意 JSP 读取/etc/shadow。
3. JDK 依赖与环境变量:8.5.35 对 Java 版本有隐性门槛
3.1 确认 JDK 版本兼容性边界
Tomcat 8.5.35官方声明支持 Java 7+,但实际运行强烈建议 Java 8u181+ 或 Java 11.0.2+。原因有三:
- Java 8u181 修复了 TLS 1.3 握手导致的
AsyncProcessor线程阻塞(影响 HTTPS 响应); - Java 11.0.2 修正了
java.nio.file.Files.walk()在高并发WEB-INF/lib扫描时的内存泄漏; - 若用 OpenJDK 8u131 或更早版本,启动时可能报
java.lang.NoClassDefFoundError: javax/annotation/PostConstruct—— 因为 JSR-250 注解被移出默认 classpath。
验证命令:
# 检查当前 JAVA_HOME 是否指向合规 JDK echo $JAVA_HOME $JAVA_HOME/bin/java -version # ✅ 合规输出示例:openjdk version "1.8.0_292" # 若未设置,临时导出(测试用) export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64 export PATH=$JAVA_HOME/bin:$PATH3.2 在 catalina.sh 中固化 JAVA_HOME,而非依赖全局环境
# 编辑 catalina.sh,找到 # OS specific support,插入以下三行(位置必须在 setenv.sh 加载之后) vim tomcat8-prod/bin/catalina.sh在# OS specific support注释块下方,紧贴if [ -r "$CATALINA_BASE"/bin/setenv.sh ]; then之前,添加:
# === BEGIN TOMCAT8.5.35 JDK FIX === if [ -z "$JAVA_HOME" ]; then export JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk" fi # === END TOMCAT8.5.35 JDK FIX ===注意:此处路径必须与你系统中
rpm -ql java-1.8.0-openjdk-headless | grep jre输出的实际路径一致。不要写.../jre,必须写.../java-1.8.0-openjdk(OpenJDK RPM 包的 JAVA_HOME 指向 JDK 根目录,非 jre 子目录)。
3.3 创建 setenv.sh 显式声明 JVM 参数(绕过 catalina.sh 硬编码)
# 创建独立配置文件,避免修改 catalina.sh(升级时易丢失) touch tomcat8-prod/bin/setenv.sh chmod +x tomcat8-prod/bin/setenv.sh写入内容(根据服务器内存调整):
#!/bin/sh # Tomcat 8.5.35 生产环境 JVM 参数(CentOS 7 x86_64, 4C8G 服务器) export JAVA_OPTS="-server \ -Xms2g -Xmx2g \ -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200 \ -Djava.awt.headless=true \ -Dfile.encoding=UTF-8 \ -Dsun.jnu.encoding=UTF-8 \ -Dorg.apache.catalina.security.SecurityListener.UMASK=0027"参数详解:
-Xms2g -Xmx2g:堆内存固定为 2GB,避免 GC 频繁扩容缩容;-XX:MetaspaceSize=256m:初始元空间设为 256MB,防止类加载过多触发 Full GC;-Dorg.apache.catalina.security.SecurityListener.UMASK=0027:强制新建文件权限为640(rw-r-----),这是 Tomcat 8.5.35 新增的安全加固项,必须显式开启。
4. 核心配置调优:server.xml 里三个不写文档却决定稳定性的参数
4.1 Connector 端口与线程模型:别再用默认 200 个 maxThreads
Tomcat 8.5.35 默认conf/server.xml中的 HTTP Connector 配置如下:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />这会导致:
maxThreads默认为 200,但未显式声明,容易被误认为可无限伸缩;acceptCount默认为 100,当瞬时请求 >300(200+100)时直接拒绝连接,返回Connection refused;- 缺少
compression="on",静态资源未压缩,浪费带宽。
必须修改为:
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="400" minSpareThreads="50" acceptCount="200" connectionTimeout="20000" redirectPort="8443" compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml,text/plain,application/javascript,application/json" />关键参数说明:
org.apache.coyote.http11.Http11NioProtocol:强制启用 NIO 模型(8.5.35 默认是 BIO,性能差 3 倍以上);maxThreads="400":根据 CPU 核数 × 100 设定(4C → 400),避免线程饥饿;compressionMinSize="2048":仅压缩 ≥2KB 的响应,规避小文件压缩 CPU 开销;noCompressionUserAgents:排除已知不支持 gzip 的古董 UA(如某些嵌入式设备)。
4.2 Engine 与 Host 的安全隔离:防止虚拟主机越权访问
默认server.xml中<Engine>未设jvmRoute,<Host>未禁用自动部署:
<Engine name="Catalina" defaultHost="localhost"> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">风险:autoDeploy="true"允许热部署,攻击者若获得webapps/写权限,可上传恶意 WAR 自动解包执行。
加固后:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="node1"> <Host name="localhost" appBase="webapps" unpackWARs="false" autoDeploy="false" deployOnStartup="false"> <!-- 禁用默认欢迎页,防止信息泄露 --> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.0\.0\.1" denyStatus="403"/> </Host> </Engine>jvmRoute="node1":为后续接入 Nginx 负载均衡做 sticky session 准备;unpackWARs="false":禁止自动解压 WAR,必须手动jar -xvf;RemoteAddrValve:仅允许本地访问 manager 页面(若启用),外部 IP 访问返回 403。
4.3 日志滚动策略:log4j2.xml 不生效?因为 8.5.35 用 JULI
Tomcat 8.5.35默认日志框架是 java.util.logging(JULI),不是 log4j2。conf/logging.properties控制所有日志行为:
# 修改 conf/logging.properties,将 catalina.out 限制为 100MB × 5 个备份 1catalina.org.apache.juli.AsyncFileHandler.level = FINE 1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs 1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina. 1catalina.org.apache.juli.AsyncFileHandler.limit = 104857600 1catalina.org.apache.juli.AsyncFileHandler.count = 5limit = 104857600:单个文件 100MB(100×1024×1024);count = 5:最多保留 5 个历史文件(catalina.2024-01-01.log.1 ~ .5);AsyncFileHandler:异步写入,避免高并发日志阻塞请求线程。
提示:若应用自身用 log4j2,需在
WEB-INF/classes/log4j2.xml中单独配置 RollingFileAppender,与 Tomcat 日志分离。二者互不影响。
5. 启动、守护与避坑:那些让你凌晨三点爬起来的翻车现场
5.1 用 systemd 托管进程:为什么不用 daemon.sh?
bin/daemon.sh是旧式 SysV init 脚本,不支持进程崩溃自动拉起、资源限制、依赖检查。现代 Linux(CentOS 7+/Ubuntu 16.04+)必须用 systemd:
# 创建 service 文件 sudo tee /etc/systemd/system/tomcat8.service << 'EOF' [Unit] Description=Apache Tomcat 8.5.35 Web Server After=network.target [Service] Type=forking User=tomcat Group=tomcat Environment="JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk" Environment="CATALINA_HOME=/opt/tomcat8/tomcat8-prod" Environment="CATALINA_BASE=/opt/tomcat8/tomcat8-prod" Environment="CATALINA_PID=/opt/tomcat8/tomcat8-prod/temp/tomcat.pid" Environment="CATALINA_OPTS=-Djava.security.egd=file:/dev/./urandom" ExecStart=/opt/tomcat8/tomcat8-prod/bin/startup.sh ExecStop=/opt/tomcat8/tomcat8-prod/bin/shutdown.sh RestartSec=10 Restart=always # 限制内存,防 OOM 杀死 MemoryLimit=3G LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF关键点:
Type=forking:Tomcat 启动脚本会 fork 子进程,必须声明;MemoryLimit=3G:systemd 层面限制总内存(JVM+Native),超限直接 kill;LimitNOFILE=65536:突破 Linux 默认 1024 文件描述符限制。
启用服务:
sudo systemctl daemon-reload sudo systemctl enable tomcat8 sudo systemctl start tomcat8 sudo systemctl status tomcat8 # 查看是否 active (running)5.2 常见问题排查:5 条血泪经验总结
现象 1:systemctl start tomcat8后状态为activating (start)卡住 90 秒,然后失败
原因:CATALINA_PID指向的路径/opt/tomcat8/tomcat8-prod/temp/不存在,或tomcat用户无写权限
解决:sudo -u tomcat mkdir -p /opt/tomcat8/tomcat8-prod/temp,并确认chown tomcat:tomcat /opt/tomcat8/tomcat8-prod/temp
现象 2:catalina.out中反复出现SEVERE [main] org.apache.catalina.startup.Catalina.load后无后续日志
原因:conf/server.xml语法错误(如多了一个</),XML 解析失败导致启动中断
解决:用xmllint --noout conf/server.xml验证 XML 格式;或临时注释掉<GlobalNamingResources>块排查
现象 3:浏览器访问http://ip:8080返回 404,但curl -I http://127.0.0.1:8080返回 200
原因:conf/server.xml中<Host>的name="localhost"与服务器 hostname 不一致,导致虚拟主机匹配失败
解决:hostnamectl set-hostname your-server-name,并在<Host>中将name改为实际 hostname,或直接删掉name属性用默认匹配
现象 4:部署 WAR 后,/manager/html页面显示应用状态为stopped,点击 Start 无反应
原因:conf/tomcat-users.xml中 manager 角色未正确映射到用户
解决:确保有如下配置(注意manager-gui和manager-script必须同时存在):
<role rolename="manager-gui"/> <role rolename="manager-script"/> <user username="admin" password="secret" roles="manager-gui,manager-script"/>现象 5:systemctl restart tomcat8后,旧进程未退出,新进程启动失败,netstat -tuln | grep :8080显示两个 PID
原因:shutdown.sh超时(默认 10 秒),未等 JVM 完全退出就返回,systemd 误判为停止成功
解决:在setenv.sh中增加export CATALINA_PID="$CATALINA_BASE/temp/tomcat.pid",并确保conf/server.xml中<Server port="8005">的 shutdown 端口未被防火墙拦截
6. 生产就绪验证与灰度技巧:用三步确认它真的能扛住流量
6.1 端口与进程级健康检查:绕过 HTTP 接口的底层验证
不能只依赖curl http://localhost:8080,要验证 Tomcat 进程本身是否健康:
# 1. 检查 JVM 进程是否存在且属主正确 ps aux | grep tomcat8-prod | grep -v grep | awk '{print $1,$2,$11}' # ✅ 应输出:tomcat 12345 /opt/tomcat8/tomcat8-prod/bin/bootstrap.jar # 2. 检查 8005 shutdown 端口是否监听(证明 Server 组件已启动) ss -tuln | grep ':8005' # ✅ 应输出:tcp LISTEN 0 1 *:8005 *:* # 3. 检查 8080 端口是否由 tomcat 用户监听(非 root) sudo lsof -i :8080 -n -P | grep LISTEN | awk '{print $1,$2,$3,$9}' # ✅ 应输出:java 12345 tomcat TCP *:8080 (LISTEN)提示:
lsof需yum install psmisc或apt install psmisc,这是生产服务器必备诊断工具。
6.2 模拟真实流量压测:用 wrk 测试连接池与 GC 表现
部署一个最小化test.war(仅含index.jsp输出OK),然后用wrk施加压力:
# 安装 wrk(Ubuntu) sudo apt install -y build-essential libssl-dev git git clone https://github.com/wg/wrk.git && cd wrk && make && sudo cp wrk /usr/local/bin/ # 对 8080 端口施加 100 并发、持续 30 秒压测 wrk -t4 -c100 -d30s http://localhost:8080/test/观察指标:
Requests/sec应 ≥ 1200(4C8G 服务器基准);tomcat8-prod/logs/catalina.out中不应出现java.lang.OutOfMemoryError: Metaspace;jstat -gc $(pgrep -u tomcat java)中MGCT(元空间 GC 次数)在 30 秒内 ≤ 2 次。
6.3 灰度发布技巧:用符号链接实现零停机版本切换
当需要升级到 8.5.36(或回滚到 8.5.34)时,绝不直接覆盖tomcat8-prod目录:
# 1. 下载新版本并解压为 tomcat8-v2 tar -xzf apache-tomcat-8.5.36.tar.gz mv apache-tomcat-8.5.36 tomcat8-v2 chown -R tomcat:tomcat tomcat8-v2 # 2. 复用原配置(关键!) cp -r tomcat8-prod/conf/ tomcat8-v2/ cp -r tomcat8-prod/webapps/ tomcat8-v2/ # 3. 原子切换(瞬间完成,无请求丢失) ln -snf /opt/tomcat8/tomcat8-v2 /opt/tomcat8/tomcat8-prod sudo systemctl restart tomcat8原理:/opt/tomcat8/tomcat8-prod是指向真实版本目录的软链。切换软链后重启服务,systemd 会加载新路径下的bin/startup.sh,而conf/和webapps/仍沿用旧配置,实现配置与代码分离。
我坚持这个做法已五年:每次升级前先ls -l /opt/tomcat8/tomcat8-prod确认软链指向,再systemctl status看进程 PID 是否变更。没有一次因升级导致业务中断。这种“土法”看似原始,但在没有 CI/CD 的传统环境中,它比任何自动化脚本都可靠——因为你能一眼看清每一步在改什么。希望帮到你。
本文还有配套的精品资源,点击获取