简介:Linux环境下的Tomcat 8.5.35压缩包,面向Java Web开发者与运维人员,用于在Linux服务器上部署与管理Java应用。该版本核心组件涵盖Catalina、Jasper、Coyote等,支持Java EE 8规范中的WebSocket、JSP 2.3、EL 3.0特性。压缩包共645个文件,约9.2MB,以html、class、java、jsp等类型为主,同时包含jar、xml、sh脚本、图片及配置文件,完整覆盖bin、conf、lib等目录,便于直接解压安装。已有555人学习下载。通过该资源可掌握标准目录结构、启动脚本、Server.xml配置及SSL/HTTPS启用方法,也可了解基于webapps部署WAR应用的流程,适合在开发、测试及生产环境中快速搭建稳定可靠的Java Web服务。
1. 为什么 2025 年还有人翻出 Tomcat 8.5.35 的 tar.gz 包
如果你接手过一些上了年纪的业务系统,大概率见过apache-tomcat-8.5.35.tar.gz这个文件名躺在某个服务器的/opt目录里。它不是最新版,8.5 系列官方生命周期早已结束,但大量存量项目还跑在它上面。我见过某公司一套内部 OA 系统,从 2019 年上线到现在没换过中间件,靠的就是这版 Tomcat 稳定、够用、不折腾。反直觉的点在于:越老的版本,越没人敢动它,因为它背后挂着一堆没人愿意碰的遗留代码和定制配置。
这篇笔记要解决的,不是「Tomcat 是什么」这种入门问题,而是当你拿到这个压缩包时,怎么在 Linux 上把它跑起来、调好参数、躲开常见的部署坑,最后能在一个生产环境里稳稳地活下来。适合的读者是两类人:一类是刚接手旧项目的运维或全栈开发,需要把这台老 Tomcat 摸透;另一类是想在本地复现老环境、做兼容测试的开发者。下面所有操作和参数,我都按生产标准来说,不是让你用个docker run糊弄过去。
2. 装机前的三件事:JDK 版本、下载校验、目录规划
2.1 JDK 版本是第一个硬门槛,装错直接翻车
Tomcat 8.5.35 是在 Java 8 时代发布的,它要求运行环境最低是 JDK 7,但实际生产里没人会用 JDK 7 跑它,主流是 JDK 8。我强烈建议你用jdk1.8.0_202或相近的 8u 版本,为什么?因为这个版本的 Tomcat 对 JDK 9 及以上版本的支持是实验性的,即使能启动,某些 JSP 编译和类加载行为会异常,你排查起来非常痛苦。
# 查看当前 Java 环境 java -version # 如果没有 JDK 或者版本不对,先装 OpenJDK 8 sudo yum install -y java-1.8.0-openjdk.x86_64 java-1.8.0-openjdk-devel # 设置 JAVA_HOME,这里以 CentOS 7 默认路径为例 echo 'export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk' >> /etc/profile echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile source /etc/profilejava -version的输出需要看到1.8.0_xxx这样的版本号。如果你机器上同时装了多个 JDK,务必确认JAVA_HOME指向的是 JDK 8,而不是系统自带的 JRE。Tomcat 启动脚本catalina.sh会读JAVA_HOME环境变量,读不到或者读错,启动会直接失败或者起一个诡异的核心转储错误。这是新手最容易踩的坑,也是很多老手在换机器部署时翻车的重灾区。
2.2 下载、校验、解压:别跳过 SHA512 校验这一步
网络上有大量 Tomcat 的下载镜像,但你不能保证你拿到手的 tar.gz 是原版、没被篡改过。官方发布包都会附带一个.sha512校验文件,下载后必须校验。我曾经见过一个模拟项目X的测试环境,因为下载了一个被注入后门的 Tomcat 包,导致服务器被拉去挖矿,血泪教训。
# 下载 Tomcat 8.5.35 二进制包和校验文件 wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.35/bin/apache-tomcat-8.5.35.tar.gz wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.35/bin/apache-tomcat-8.5.35.tar.gz.sha512 # 校验哈希值,Linux 自带工具 sha512sum apache-tomcat-8.5.35.tar.gz cat apache-tomcat-8.5.35.tar.gz.sha512对比两个输出是否一致,不一致就立刻扔掉重新下载。这一步不是形式主义,国内镜像站的历史上出现过不同步的缓存文件。校验通过后,解压到规划好的目录。我的习惯是把 Tomcat 放在/opt下,而不是/usr/local,因为/opt更适合放第三方独立软件,升级和备份时整目录操作更方便。
# 解压并重命名为规范的服务名 tar -zxvf apache-tomcat-8.5.35.tar.gz -C /opt mv /opt/apache-tomcat-8.5.35 /opt/tomcat8 # 创建一个普通用户来运行 Tomcat,不要用 root useradd -r -s /sbin/nologin tomcat chown -R tomcat:tomcat /opt/tomcat8这里有个重要逻辑:永远不要用 root 跑 Tomcat。Tomcat 本身有权限提升漏洞的话(比如 CVE 相关),root 运行会直接把服务器拱手让人。生产环境里我会创建专用用户,并限制其登录权限,这样即使被突破,攻击者也只是在一个受限账户里打转。
2.3 目录结构:bin、conf、webapps、logs 各自管什么
解压后你会看到一堆目录,先搞清它们的职责,后续修改参数时你才知道往哪找。bin目录存放启动/关闭脚本,包括startup.sh、shutdown.sh、catalina.sh、version.sh等。conf目录是所有配置的中心,server.xml负责端口和连接器,web.xml是全局默认的 Servlet 配置,catalina.properties控制类加载路径。webapps是放置 Web 应用的位置,一个子目录就是一个应用,.war包丢进去会自动解压部署。logs目录的日志文件是排错的第一现场。lib目录存放 Tomcat 自身和公用的 jar 包。
# 查看目录结构 ls -l /opt/tomcat8文件权限也要留意:bin下的脚本必须有执行权限,conf目录下的文件必须对运行用户可读。如果你发现startup.sh无法执行,先看权限是不是丢了,用chmod +x修复。目录规划这块,重点是把选择权握在自己手里,别被系统默认路径带着走。
3. 让 Tomcat 跑起来:最小启动命令与第一轮排错
3.1 前台启动与后台启动:先看日志,再放后台
拿到一个干净的 Tomcat,第一轮验证不应该是直接双击startup.sh然后傻等。我推荐先在前台跑,这样控制台会实时打印日志,任何启动异常都能第一眼看到。最小命令是:
# 前台启动,看实时日志 /opt/tomcat8/bin/catalina.sh run如果日志滚动到Server startup in [xxx] milliseconds,说明启动成功,按Ctrl+C停掉。然后放后台:
# 后台启动 /opt/tomcat8/bin/startup.sh # 确认进程存在 ps -ef | grep tomcatstartup.sh本质上也是调用catalina.sh start,它会启动一个独立的 Java 进程然后返回。注意,startup.sh启动后不会在终端打印日志,日志写入logs/catalina.out。这也是为什么我坚持先跑一次run,因为catalina.out里记录的启动信息很多是静态的,前台模式下你能及时中断,避免问题被日志缓冲掩盖。
3.2 第一个验证点:8080 端口和默认首页
启动后第一件事是验证端口监听。Tomcat 默认 HTTP 连接器是 8080,你可以用以下命令确认:
# 查看端口监听状态 netstat -tlnp | grep 8080 # 如果有输出,说明 socket 已就绪 # curl 验证默认首页 curl -I http://127.0.0.1:8080/如果返回HTTP/1.1 200,Tomcat 已经工作正常。这一步是对刚才启动动作的闭环验证,不要跳过。如果 curl 不通但端口监听存在,检查服务器防火墙和云安全组的放行规则。注意netstat -tlnp需要 root 权限才能看到完整进程名,你可以在ps -ef里对照 PID 来判断那确实是 Java 进程。
3.3 部署一个最简应用:从 war 包到解压目录
Tomcat 的部署机制很简单,把 war 包丢进webapps目录就会自动解压发布。为了验证部署路径没问题,我用一个空壳 war 包测试:
# 在 webapps 下建一个最小应用,模拟 war 包解压后的结构 mkdir -p /opt/tomcat8/webapps/testapp/WEB-INF # 写一个最基础的 web.xml cat > /opt/tomcat8/webapps/testapp/WEB-INF/web.xml <<'EOF' <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> </web-app> EOF # 放一个测试页 echo "Hello Tomcat 8.5.35" > /opt/tomcat8/webapps/testapp/index.html # 重启 Tomcat 让应用生效 /opt/tomcat8/bin/shutdown.sh /opt/tomcat8/bin/startup.sh # 验证访问 curl http://127.0.0.1:8080/testapp/这里的关键点是web.xml不是可选的,Tomcat 8.5 虽然支持 Servlet 3.1 的注解扫描,但一个无web.xml的应用目录仍然可能被跳过部署。很多新手把 war 包丢进去后访问 404,第一反应是配置错了,其实只是解压出来的目录里缺了WEB-INF结构。另外,shutdown.sh执行后建议用ps -ef确认进程真正退出再启动,因为旧的 Java 进程如果没死透,新进程会因端口被占用直接报错。
3.4 端口被占用怎么办:改 server.xml 的套路
如果 8080 被别的服务占了(比如另一个 Tomcat 实例或者某个 Spring Boot 应用),启动日志会报BindException: Address already in use。这个问题的解决不是杀进程硬抢端口,而是修改conf/server.xml:
<!-- conf/server.xml 中修改 Connector 端口 --> <Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />我一般不会用默认 8080,而是改成 8081 或 18080 这类不常用的端口,减少和其他服务撞车的概率。改完后重启验证,改端口时注意redirectPort也要同步调整,这个参数决定了 HTTP 重定向到 HTTPS 时用哪个端口,改漏了会导致跳转 404 或端口错误。
4. 生产级参数调优:JVM、连接器、线程池一个都不能少
4.1 在 catalina.sh 里配 JVM:Java 8 下的典型参数组合
Tomcat 默认的 JVM 参数是很保守的,生产环境直接跑默认参数等于浪费硬件资源。我一般在catalina.sh开头的注释块后面新增一段JAVA_OPTS,而不是改默认值。
# 在 catalina.sh 中找到 # OS specific support 之前插入 JAVA_OPTS="-server -Xms1024m -Xmx1024m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/tomcat8/logs/heapdump.hprof"逐个说明:-server是服务端 JVM 模式,默认在 64 位 Linux 上通常是 server,但写明确更保险;-Xms和-Xmx设置初始和最大堆,生产上我习惯设为相同值,避免堆动态伸缩带来的性能抖动;MetaspaceSize是 JDK 8 里替代永久代的区域,给 256m 对绝大多数应用够用了。UseConcMarkSweepGC是 JDK 8 时代最稳妥的并发 GC,但注意它是老年代 GC,新生代默认配的是 ParNew。
如果你用的应用是 Spring Boot 打成的 war 跑在 Tomcat 上,或者有频繁创建和销毁对象的逻辑,GC 参数还需要结合实际情况调。但有一条原则:HeapDumpOnOutOfMemoryError和HeapDumpPath一定要配,OOM 时生成的 hprof 文件是你事后分析问题的唯一现场证据。
4.2 连接器参数:maxThreads 和 acceptCount 决定谁先被拒
Tomcat 8.5 默认 HTTP 连接器工作在 NIO 模式,但线程池的默认参数偏低。在conf/server.xml的<Connector>节点上,我会补上这几个参数:
<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" maxThreads="400" acceptCount="200" minSpareThreads="40" maxConnections="10000" redirectPort="8443" />maxThreads是最大工作线程数,处理业务请求的线程就这么多。我给的 400 算是中等值,具体看你的 CPU 核数和应用响应时间。如果应用单个请求要几百毫秒,400 线程已经能让 CPU 压力很高了。acceptCount是等待队列长度,队列满了之后新的连接会被拒绝。minSpareThreads是空闲线程下限,保证流量高峰期不用临时创建线程。maxConnections是 TCP 层面的最大连接数,它和maxThreads不同,后者是并发处理请求的线程数,前者是 accept 的连接数,你把它当做一个大号的缓冲池来理解。
4.3 内存问题排查:看看 metaspace 是不是被撑爆了
生产实践里,Java 应用最常见的诡异故障是OutOfMemoryError: Metaspace,而不是堆内存溢出。Metaspace 存的是类元数据,每次重新部署 war 包、或者热加载类,Metaspace 都会增长。我见过一个跑了好几年的 Tomcat,每次发版都 Full GC,最后在某次发版后直接起不来,后台日志报Metaspace exhausted。
这问题的根源不是配置参数错误,而是应用自身类加载逻辑有泄漏。但在 Tomcat 侧,你可以先调大上限并观察曲线:
# 观察内存使用情况 jmap -heap $(pgrep -f "catalina")看输出里的MetaspaceSize和MaxMetaspaceSize参数,再用jstat -gcutil看 Metaspace 的使用率百分比。如果说MaxMetaspaceSize已经顶满,而Full GC频率一直很高,那是应用的问题,你调大参数只是拖延爆炸时间。这种场景我最常用的临时应急手段是加大MaxMetaspaceSize,但必须同时让开发从类加载器释放的角度查问题的根因。
4.4 生产环境的安全基线:删除默认应用、隐藏版本号
Tomcat 默认带了一堆示例应用(examples、docs、manager、host-manager),这些在本地学习有用,生产环境是纯多余的安全暴露面。我部署时先删干净:
rm -rf /opt/tomcat8/webapps/docs rm -rf /opt/tomcat8/webapps/examples rm -rf /opt/tomcat8/webapps/manager rm -rf /opt/tomcat8/webapps/host-manager rm -rf /opt/tomcat8/webapps/ROOT另外,HTTP 响应头里的Server: Apache-Coyote/1.1会暴露 Tomcat 版本号,攻击者以此为线索去找对应版本的 CVE。改法是在conf/server.xml里的<Host>标签内加一个errorReportValveClass配置,或者自定义一个错误页 Valve。我常用一个更轻量的方案:在conf/web.xml里把默认的 404、500 错误页替换成自己写的空页面,这样既不让版本信息直接露出来,用户体验也更好。
5. 8.5.35 日常运维避坑:四个高频事故的「现象 → 原因 → 解决」
5.1 现象:Tomcat 启动成功,但访问时 intermittent 的 503 或 Connection reset
这种问题最让人抓狂,表面上看服务正常,curl 几次通一次挂一次。原因多半是连接器的acceptCount设置太小,加上应用响应太慢,导致新连接被内核拒绝。我遇到过某公司跑报表服务的模拟项目X,查询一个报表要 30 秒,前端超时设的是 10 秒,客户端重试机制打开,一秒钟打进来几百个请求,Tomcat 直接雪崩。解决方法是逐步调大maxThreads和acceptCount,同时给前端加一个请求合并或限流,不让瞬时流量直接怼进 Tomcat。
5.2 现象:Tomcat 重启后 session 全部失效,用户被踢下线
这是分布式环境里的经典问题。Tomcat 默认的 session 保存在本地内存,重启即失。如果负载均衡后面挂了多个节点,session 还存在单台内存里,那这台机器一重启,落在它上面的用户全部要重新登录。解决路径两条:一是引入 Session 共享(用 Redis 或数据库存储),二是改web.xml里的 session 持久化方式。不过 8.5.35 这个老版本,我建议不要过度依赖它的持久化机制,直接上外置存储更省心。
5.3 现象:日志里大量SEVERE: Error filterStart或Context [...] startup failed
这种报错几乎不交代真正的原因,只告诉你过滤器启动失败。原因通常有三种:应用依赖的 jar 包冲突、web.xml里配置的 filter 类找不到、或者某个第三方库初始化依赖了外部配置。解决手段是先看应用自己的日志(println 输出到 catalina.out),再看有没有 ClassNotFoundException 或 NoSuchMethodError。我的排查顺序是:先确认 lib 目录下的 jar 有没有重复或版本冲突,再用verbose方式启动看完整类加载过程。
5.4 现象:运行几个月后磁盘满了,catalina.out 单文件几十 GB
这是没人管理的老 Tomcat 的通病。Tomcat 默认把 stdout 重定向到catalina.out,应用里所有System.out.print都写进去,时间一长文件大得可怕。解决思路两件事:第一是定期切割日志,用logrotate配一个按天切分、保留 7 天的策略;第二是从应用侧禁用无意义的System.out输出,全部走 log4j 或 logback。logrotate的具体配置直接建一个新文件放到/etc/logrotate.d/下面就行。
# /etc/logrotate.d/tomcat /opt/tomcat8/logs/catalina.out { daily rotate 7 compress copytruncate missingok }copytruncate参数是关键,因为 Java 进程持有文件句柄,copytruncate会先复制后清空原文件,避免重启 Tomcat 才能让日志轮转生效的尴尬。
6. 验证与升级前的最后一步:用全链路检查确认 8.5.35 没虚焊
先更新手上这台 Tomcat 的版本号验证方式,bin/version.sh可以拿到精确的版本输出:
/opt/tomcat8/bin/version.sh随后做一次完整的健康检查脚本。我习惯把它写成一个一次性脚本跑一遍,覆盖进程、端口、应用、JVM 状态四个层面:
#!/bin/bash # 检查进程 pgrep -f "org.apache.catalina.startup.Bootstrap" > /dev/null && echo "进程存活" || echo "进程不存在" # 检查端口 netstat -tlnp | grep 8081 # 检查应用响应码 curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8081/testapp/index.html # JVM 堆使用率超过 90% 则告警 jstat -gcutil $(pgrep -f "catalina" | head -1) | awk 'NR>1 && $4>90 {print "老年代使用率偏高:", $4"%"}'把pgrep -f的模式调整成你实际目录路径,这个脚本可以直接放进 crontab 每分钟跑一次,成本很低。如果后续要从 8.5.35 升级到新版(8.5 后期或 9.x),我的建议不是直接覆盖安装,而是复制一份conf/server.xml、conf/web.xml和lib目录清单,确认你的自定义配置全部能对上新版的文件格式再动。Tomcat 8.5.x 的server.xml结构大体兼容后续版本,但Connector的某些属性名有细微变化,盲目复用老配置在新版上可能会被忽略甚至报错。
最后聊一件我自己的教训:有一回我给一台老 Tomcat 加了一个定期重启的 crontab,理由是「反正它内存泄漏跑久了就卡」。那台机器一上午被重启了三次,业务方直接投诉。老 Tomcat 的毛病是问题积累出来的,不是靠重启混过去的。正确的做法是用 jstat 连续观察一周的 GC 和内存趋势,确认泄漏再动手修;修不了就定好维护窗口,一次性升级,而不是每天撞运气。希望帮到你。
本文还有配套的精品资源,点击获取