简介:Linux 版 Tomcat 8.5.35 压缩包面向 Java Web 应用开发者与运维人员,用于在 Linux 环境快速部署 Servlet 容器,解决应用上线与调试中的服务器搭建问题;这套软件集合了核心组件,支持 WebSocket、JSP 2.3、EL 3.0 等新特性,适配从开发测试到生产发布的多种场景。资源包大小约 9.2MB,共 645 个文件,类型涵盖页面模板、动态脚本、源码与编译产物、依赖库、配置文件等,可据此了解 Web 应用的组织方式和 Tomcat 的配置要点。压缩包采用标准目录结构,启动停止脚本、服务配置、共享库、日志、临时目录与应用部署目录一应俱全,解压后调整环境变量即可完成基础安装。资源描述还涉及环境变量配置、访问控制与启用安全连接的思路,对新手部署和运维排错有一定参考价值;目前已有 548 人学习浏览,适合需要获取官方版本并快速上手 Linux 环境部署的开发者。
1. 从tar.gz到可运行实例:先弄明白这个包到底在干什么
很多刚从Windows转过来的朋友,第一次看到tomcat8-8.5.35.tar.gz这个文件名,会下意识把它当作"安装包"——点一下、下一步、安装完成。但在Linux环境里,这个文件本质上只是一个用tar打捆、再用gzip压缩的归档文件,里面装的是Tomcat的完整目录树,不是安装程序。它的部署逻辑是"解压即用",而不是"安装到系统"。
我先说结论:tar.gz解压后,Tomcat不需要任何编译、不需要写注册表、不需要改环境变量(除非你要在任意目录执行catalina.sh),它就是以CATALINA_HOME为核心的绿色软件。你需要的仅仅是三个前置条件:一个能跑的JDK、一个可用的JAVA_HOME环境变量、以及一个非root的运行用户。
再说说8.5.35这个具体版本。熟悉Tomcat版本号的同学会知道,8.5.x系列在2016到2022年间走了很长的维护周期,8.5.35发布于2019年中旬,对应的是Java EE 7规范和Servlet 3.1规范,兼容JDK 7及以上,但实测最稳的是JDK 8。这个版本在当年的生产环境里非常普及,网上能找到的踩坑经验也最多,拿它来上手或者做存量项目部署,性价比很高。如果你要部署的是老项目,还要求Servlet 3.1、WebSocket、NIO连接器这些特性,8.5.35完全够用;如果要跑最新的Spring Boot 3.x或Jakarta EE 9+应用,那就要考虑Tomcat 9/10甚至11了,这是后话。
操作的整个思路分成四步:环境准备、解压落位、配置调优、启动验证。每一步都有容易翻车的小细节,我下面逐一展开。
2. 环境准备阶段最容易被忽略的两个检测点
2.1 JAVA_HOME没配好,后面全是白忙
Tomcat的启动脚本catalina.sh和setclasspath.sh严格依赖环境变量JAVA_HOME或JRE_HOME。如果你的环境里已经装好了JDK,但不习惯把JAVA_HOME写进/etc/profile或~/.bashrc,那么执行startup.sh时会直接报:
Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At least one of these environment variable is needed to run this program注意,这一步报错其实还算友好,最坑的是你配了JAVA_HOME,但配错了路径。比如有的发行版用yum install java-1.8.0-openjdk装的JDK,它的真实安装路径散落在/usr/lib/jvm/下,你如果随手填一个/usr/java/jdk1.8.0_xxx,启动脚本找不到bin/java,会给出一个让人摸不着头脑的提示:
Cannot find /path/to/your/wrong/jdk/bin/java The file is absent or does not exist稳妥的做法是,用which java和readlink -f $(which java)两级命令把真实路径追出来:
which java # 输出: /usr/bin/java readlink -f /usr/bin/java # 输出: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.282.b08-1.el7_9.x86_64/bin/java记住,JAVA_HOME要填到bin的上一级,也就是/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.282.b08-1.el7_9.x86_64,不是填到bin/java。修改/etc/profile后记得source /etc/profile,然后echo $JAVA_HOME验证,别跳步。
2.2 用有没有现成的tomcat用户,不要一上来就root
安全习惯要先养成。Tomcat作为对外提供HTTP服务的进程,如果以root身份运行,一旦被攻破,整个服务器就等于是人家的了。比较标准的做法是创建一个专用的系统用户,比如:
useradd -r -s /sbin/nologin tomcat然后把这个用户作为CATALINA_HOME目录的属主:
chown -R tomcat:tomcat /usr/local/tomcat后面启动的时候用su - tomcat -c '/usr/local/tomcat/bin/startup.sh'切到该用户执行。这种安排还能避免另一个问题:如果你用root启动过Tomcat,生成的logs、work、temp目录里会留下root属主的文件,切换普通用户后很可能会遇到"Permission denied"的写入报错。先建用户再解压,或者解压后立刻改属主,能省掉一路上的权限烦恼。
3. 解压、落位、初始化:把Tomcat放到它该在的位置
3.1 标准解压命令与目录规划
在/usr/local下操作最省心,上传完成后执行:
cd /usr/local tar -zxvf tomcat8-8.5.35.tar.gz-z表示通过gzip解压,-x表示解压,-v是显示过程,-f指定文件名。如果你下了别的压缩格式,比如.tar.xz,命令就变成tar -Jxvf,千万别看到.tar.gz就一路tar -zxvf,格式不对会直接报gzip: stdin: not in gzip format。
解压完会得到类似apache-tomcat-8.5.35这样的目录。我个人的习惯是保留这个原始目录名,然后在/usr/local下面建一个tomcat软链接指向它:
ln -s /usr/local/apache-tomcat-8.5.35 /usr/local/tomcat好处很实在:以后升级版本时,新的包解压出来后,只要把软链接重新指一下,所有依赖/usr/local/tomcat这个路径的脚本、systemd服务、监控配置全部不用改。别小看这个细节,很多生产事故就是升级时改了实际目录名,漏改了某个配置文件里的绝对路径造成的。
3.2 目录结构里每个文件夹是干嘛的,别乱动
解压后你会看到bin、conf、lib、logs、temp、webapps、work这七个关键目录:
bin:存放启动、关闭脚本,startup.sh、shutdown.sh、catalina.sh都在这里。catalina.sh才是最核心的脚本,前两个本质上是它的一层薄封装。conf:所有配置文件,server.xml(核心配置)、web.xml(全局Servlet配置)、context.xml(JNDI和全局上下文)。lib:Tomcat自身的JAR包,比如servlet-api.jar、catalina.jar。这个目录很敏感,除非你知道自己在干嘛,否则不要往里塞应用级依赖。logs:日志输出目录,catalina.out是控制台标准输出和错误输出的合并文件,排查问题第一眼看它。webapps:放Web应用的地方,一个子目录就是一个应用。默认带ROOT、docs、examples、host-manager、manager五个应用。work:JSP编译后的class文件缓存目录。JSP被修改后,Tomcat会重新编译,但偶尔也会出现"改了代码没生效"的问题,清空work目录是第一个排查手段。temp:临时文件存储,别手动往里放东西。
部署普通Web项目时,最常见的做法就是把打好的war包扔进webapps目录,然后Tomcat启动时自动解压、自动部署。但生产环境我更推荐指定外部docBase的方式,这个后面讲server.xml的时候再细说。
4. server.xml调优与JVM参数落位:从"能跑"到"跑得稳"
4.1 server.xml里值得改的四个地方
conf/server.xml是Tomcat的主配置文件。我想说的是,默认配置足够启动,但如果你直接拿默认配置上生产,大概率会踩到下面这些点。
端口配置与单机多实例:默认监听8080,管理端口8005,AJP端口8009。单机只跑一个Tomcat,不用改。但一台机器要跑多个Tomcat实例(比如多个环境隔离),就需要把这三处端口全部改掉,否则第二个实例启动时会报端口占用错误。注意8005是shutdown端口,只允许本机连接,做多实例时不要忘记改它。
连接器参数:这是影响吞吐量的关键。<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />里建议显式设置maxThreads、acceptCount、minSpareThreads。我常用的初始配置是:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxThreads="400" minSpareThreads="50" acceptCount="200" maxConnections="10000" URIEncoding="UTF-8"/>解释一下每个参数的含义:maxThreads决定请求处理线程的上限,默认只有200,对稍微有点并发量的系统就不够用;acceptCount是请求队列长度,排队等待线程处理的最大请求数;URIEncoding="UTF-8"是为了解决GET请求中文参数乱码问题,这是老生常谈但真有人不设。这里有个思路要说清楚:线程数不是越大越好,每增加一个线程都要吃内存,线程过多还会导致上下文切换开销剧增。合理范围取决于你的机器核数和单请求耗时,一般先设到300-500,压测后再调。
Host的appBase与热部署:默认的<Host name="localhost" appBase="webapps">配合autoDeploy="true"意味着你把war丢进webapps目录,Tomcat会自动部署。开发环境很好用,但生产环境我建议把应用目录放到webapps外,用docBase指定:
<Host name="localhost" appBase="webapps" autoDeploy="false" deployOnStartup="true"> <Context path="" docBase="/data/myapp" reloadable="false"/> </Host>这样应用和Tomcat本体分开存放,以后升级Tomcat时不用把应用一起搬走,应用的日志、临时文件也不会污染Tomcat目录。reloadable生产环境必须设为false,否则它会定期扫描class变化,消耗性能且容易触发莫名其妙的ClassLoader泄漏。
Valve日志:默认的AccessLogValve在localhost_access_log.*.txt里记录每个HTTP请求。生产环境建议保留,它是排查问题的第一手材料。
4.2 JVM参数:setenv.sh是每个Linux运维都应该知道的东西
很多人直接改catalina.sh里的JAVA_OPTS,这其实是个坏习惯,因为每次升级Tomcat、重新解压后,你的修改就丢了。Tomcat官方留了一个扩展点位:bin/setenv.sh。如果这个文件不存在,你创建一个,启动脚本会自动加载它。
#!/bin/bash JAVA_OPTS="-server -Xms1024m -Xmx1024m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -Djava.awt.headless=true -Dfile.encoding=UTF-8"这里-Xms和-Xmx保持一致,避免堆大小在运行期动态伸缩带来的性能抖动;-Xmx的具体值取决于服务器物理内存,一般建议不要超过系统内存的1/2,留一部分给文件缓存和系统自身。Metaspace是JDK 8以后替代PermGen的区域,默认没有上限的,显式设置一下反而更稳。headless参数是给服务器环境用的,避免图像处理相关的库在无显卡环境下报错。
4.3 启动慢的问题:熵池不足与等待时机
在部分云服务器上(尤其是刚创建的虚拟机),Tomcat启动卡在几十秒甚至几分钟才完成,日志里出现这样的提示:
INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [230,534] milliseconds.这个问题的根源是JVM生成session ID时要用到SecureRandom,它依赖操作系统内核的熵池。某些云服务器上熵池不够,随机数生成被阻塞。解决思路有两个方向:第一个是在catalina.sh里给JAVA_OPTS加上-Djava.security.egd=file:/dev/./urandom,改用非阻塞的urandom;第二个方向是装rng-tools,用硬件随机数或虚拟随机数补充熵池。实测下来第一个方向见效最快,改一行就够。
5. 启动、关闭与常见报错排查:一次完整的问题处理链路
5.1 第一次启动与日志观察
在/usr/local/tomcat/bin目录下执行:
./startup.sh启动脚本会输出一行Tomcat started.,但说实话,这行字并不代表启动成功了,只代表启动进程被成功拉起。真正的判断标准是看日志和端口。
tail -f /usr/local/tomcat/logs/catalina.out看到Server startup in [xxxx] milliseconds才算完整启动。然后验证端口监听:
ss -lntp | grep 8080再用curl验证HTTP响应:
curl -I http://127.0.0.1:8080如果返回了HTTP/1.1 200,那这台Tomcat的对外服务才算真正就绪。只看到Tomcat started但端口没起来,常见原因是server.xml配错了、端口被占用、或者JVM参数写错了导致进程闪退。这些都要靠catalina.out里的异常信息去对号入座。
5.2 端口占用:启动失败的常见元凶
如果日志里出现了:
SEVERE: Failed to initialize end point associated with ProtocolHandler ["http-nio-8080"] java.net.BindException: Address already in use: JVM_Bind <null>:8080说明8080端口已经被别的进程占了。先用ss -lntp | grep 8080看是谁,然后按实际情况处理:如果是另一个Tomcat实例,要么停掉它,要么改端口;如果是别的应用,就要重新规划端口分配。
这里有个操作细节:很多人习惯直接kill -9杀掉Tomcat进程,我劝你尽量别这样。正常关闭应该用shutdown.sh,它会走完标准关闭流程,通知连接器停止接收新请求、等待正在处理的请求结束、触发ServletContextListener的销毁方法。直接kill -9等于把这些清理步骤全部跳过,长此以往,连接器线程、数据库连接池这些资源可能就不会被正确释放,在下一次启动时出现"端口明明没监听,但就是绑定不了"的诡异现象。
如果shutdown.sh之后进程还活着(有时候因为应用线程卡住关不掉),可以用jps或ps -ef | grep tomcat找到PID,先kill PID,等几秒后再kill -9,这个过程要有耐心。
5.3 启动404与AppBase的坑
有人启动后访问http://IP:8080看到404,第一反应是Tomcat坏了。实际上最常见的两个原因:一个是解压时用root执行的,webapps/ROOT目录权限不对,Tomcat进程没法读取,导致根应用没起来;另一个问题是默认的ROOT应用被人删掉或破坏。检查方式很简单:
ls -l /usr/local/tomcat/webapps/ROOT如果这个目录不存在,或者里面是空的,访问8080自然就是404。解决方案:把8.5.35压缩包里的webapps/ROOT目录重新解压一份出来,或者干脆部署你自己的应用。
5.4 APR native library提示,不影响运行但要心里有数
启动日志里经常会看到一行:
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib]这行的意思是:Tomcat没找到APR本地库(tcnative),所以连接器回退到了纯Java的NIO模式。Tomcat依然能正常工作,只是少了一个基于OpenSSL和系统级异步IO的性能优化选项。如果生产环境对并发和TLS性能要求很高,可以去编译安装tomcat-native;如果只是普通业务系统,暂时不装也完全可以。网上那些说"不装APR就卡死"的说法,多数是把性能优化和功能性故障混为一谈了。
6. 开机自启与部署经验:把Tomcat纳入系统adult管理
到了这个阶段,Tomcat已经能稳定跑起来了。但每次机器重启后手动执行startup.sh,不是一种专业做法。在CentOS 7/RHEL系上,标准的做法是写一个systemd服务单元。
在/etc/systemd/system/tomcat.service里写入:
[Unit] Description=Apache Tomcat 8.5.35 After=network.target [Service] Type=forking User=tomcat Group=tomcat Environment=JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.282.b08-1.el7_9.x86_64 Environment=CATALINA_HOME=/usr/local/tomcat Environment=CATALINA_BASE=/usr/local/tomcat ExecStart=/usr/local/tomcat/bin/startup.sh ExecStop=/usr/local/tomcat/bin/shutdown.sh Restart=on-failure [Install] WantedBy=multi-user.target注意Type=forking,因为startup.sh会启动一个后台进程然后立即返回,和systemd的forking模式完全吻合。写完以后:
systemctl daemon-reload systemctl enable tomcat systemctl start tomcat开了enable之后,系统重启时Tomcat会跟着起来。Restart=on-failure的意思是,如果进程异常退出,systemd会自动把拉起来。
说到部署经验,这里再补一个WAR包更新的顺序问题。很多人更新应用时直接把新war丢进webapps覆盖旧的,这容易出问题。推荐的做法是:先停Tomcat,把旧war和同名解压目录一起删掉,放新war,再启动。如果你的环境不方便停服,那至少也要确保Tomcat处于运行状态,因为Tomcat默认autoDeploy="true"时会监听webapps目录的文件变化,它自己能处理war覆盖和重新解压。但这个过程偶尔会有各种classloader问题,为了求稳,冷部署还是比热部署可靠,代价只是几十秒钟的停机窗口。
关于shutdown.sh关不掉进程的情况,我遇到过一次比较典型的:应用里有个线程池,线程持有非守护线程标志,ServletContext销毁时没有调用executor.shutdown(),导致JVM永远无法退出。这个问题在命令行敲shutdown.sh后,日志也打了Stopping service Catalina,但进程就是不死。排查思路:用jstack PID抓到线程dump,找到那种RUNNABLE状态且堆栈里卡在socketAccept或take上的业务线程,去代码里找对应的close()或shutdown()调用,把资源清理逻辑补上。
7. 部署后的几个常规检查项(个人实测经验)
分享几个我自己的习惯,每次部署完Tomcat都按这个列表过一遍:
curl -I先访问根路径,确认HTTP层通。- 检查
catalina.out里有没有SEVERE或ERROR级别的日志,WARN可以先放一放。 - 用
jps -lv确认Java进程的启动参数和预期的JVM参数一致,有时候setenv.sh没生效你都不知道。 - 检查
/usr/local/tomcat/logs/localhost_access_log.*.txt里有没有出现异常状态码(如大量500、503)。 - 确认防火墙放行了8080端口(如果用了firewalld,是
firewall-cmd --add-port=8080/tcp --permanent && firewall-cmd --reload)。
最后关于这个tar.gz版本的下载渠道,多说一句:尽量从Apache官网或你公司私服的制品库拿包,不要在网盘、论坛等渠道下载来路不明的二进制包,毕竟Web服务器是直接暴露在公网上的入口,包的完整性校验(md5sum或sha256sum)在解压之前做一做,有这习惯的人不多,但很值得。
本文还有配套的精品资源,点击获取