两个Tomcat同时装在一台服务器上,最需要改的是三处:server.xml里的三个端口、环境变量CATALINA_HOME和CATALINA_BASE、JVM内存参数;如果分别装在两台服务器,要改的是Nginx连接配置和会话保持策略。
把两个Tomcat放进同一台服务器,很多人第一反应是“改端口就行”,但实际操作中至少还有三类配置需要同步调整,端口只是最表层的问题,环境变量互相覆盖、JVM内存互相抢占才是隐藏的雷区,下面从实战出发,按优先级逐一说清楚哪些地方必须动手。
同机双Tomcat优先改端口:server.xml里三个数字必须错开
先解决最直观的问题:端口冲突,标准Tomcat安装后默认监听三个端口,8080是HTTP请求入口,8005是shutdown指令专用端口,8009是AJP协议通信端口,当你把第二个Tomcat解压到同一台机器上,如果不去动server.xml,启动时一定会看到类似 java.net.BindException: Address already in use 的报错,因为三个端口都被第一个实例占着。
修改路径是 conf/server.xml,需要动三处:
- 第一处:HTTP Connector,找到
<Connector port="8080" ...>,把8080改成8081或8082 - 第二处:shutdown端口,找到
<Server port="8005" shutdown="SHUTDOWN">,把8005改成8006或8007 - 第三处:AJP端口,找到
<Connector port="8009" ...>,把8009改成8010或8011
很多人只改8080就以为完事了,结果启动成功却无法通过shutdown脚本正常停止服务,或者AJP协议冲突导致莫名报错,三个端口必须同时错开。
| 配置位置 | 默认端口 | 第二个实例建议值 |
|---|---|---|
| HTTP Connector | 8080 | 8081 |
| Shutdown 端口 | 8005 | 8006 |
| AJP Connector | 8009 | 8010 |
改完端口后,记得同步调整防火墙和安全组规则,如果服务器有iptables或firewalld,需要放行新端口;如果用的是简米云、酷番云这类云主机,还要在控制台安全组里把8081、8006、8010加入入方向规则,否则外部访问仍然不通。

CentOS服务器部署两个Tomcat冲突怎么解决:问题常在环境变量
端口改完,第二个Tomcat往往能启动,但日志错乱、关闭时把第一个实例的进程杀掉、页面加载的资源来自另一个项目……这些才是双Tomcat冲突最典型的症状,行业共识认为,绝大多数这类问题都出在环境变量配置上,而不是端口。
CentOS上最常见的错误写法,是把 CATALINA_HOME 写进 /etc/profile 或 ~/.bashrc,然后解压两份Tomcat,两份都去读同一个 CATALINA_HOME,表面上两个实例能启动,实际启动脚本调用的 bin 目录、读取的 conf、写入的 logs 全部指向第一份,你访问第二个Tomcat的8081端口,加载的可能是第一个Tomcat的webapps内容。
服务器双Tomcat环境变量修改方案:用setenv.sh代替全局配置
标准做法是每个Tomcat实例下单独建一个 bin/setenv.sh 文件,把环境变量写在这个脚本里,而不是写进系统全局配置,启动时 catalina.sh 会优先加载 setenv.sh,这样就能隔离两个实例。
假设你的目录结构是:
/usr/local/tomcat1,对应项目A,端口8080/usr/local/tomcat2,对应项目B,端口8081
那么在 /usr/local/tomcat2/bin/setenv.sh 中写入:
export CATALINA_HOME=/usr/local/tomcat2 export CATALINA_BASE=/usr/local/tomcat2
同时把 /etc/profile 里原来的 CATALINA_HOME 注释掉,避免全局变量覆盖局部设置,这样两个实例各自读各自的配置,日志分家,关闭命令也不会误伤对方。
两个Tomcat切换端口设置教程:不要忽视CATALINA_BASE
这里要单独说一下 CATALINA_BASE,很多教程只强调 CATALINA_HOME,却忽略了它和 CATALINA_BASE 的差别。CATALINA_HOME 指向Tomcat程序文件所在目录,CATALINA_BASE 指向实例运行时的配置文件目录。
如果两个Tomcat是完全独立的两份拷贝,CATALINA_HOME 和 CATALINA_BASE 指向同一个路径没问题,但如果为了节省磁盘空间,只放一份Tomcat程序,用两份conf目录创建两个实例,就必须让 CATALINA_BASE 分别指向各自的conf、logs、webapps目录,一个典型的切换场景:
- 第一个实例:
CATALINA_BASE=/data/tomcat-instance1 - 第二个实例:

CATALINA_BASE=/data/tomcat-instance2
这样的好处是,升级Tomcat版本时只需要替换一份 CATALINA_HOME,两个实例的配置和部署目录不受影响,但由于 CATALINA_BASE 同时决定了日志位置和临时目录,一旦配错,两个实例会共用同一个logs目录,日志文件名互相覆盖,排查问题时很难分清是哪个实例的报错。
JVM内存参数:两个Tomcat抢内存不是改代码
端口不冲突、环境变量隔离好,双Tomcat还有一个容易踩的坑:JVM内存分配,默认Tomcat启动时,catalina.sh 会读取 JAVA_OPTS 环境变量,如果在 /etc/profile 里全局设置过 JAVA_OPTS="-Xms512m -Xmx1024m",那么两个Tomcat会同时尝试申请最大1GB堆内存,当物理内存只有2GB时,第二个实例大概率启动失败,或者运行一段时间后触发OOM被系统杀掉,现象就是Tomcat进程莫名其妙消失。
正确做法是把JVM参数写进各自的 setenv.sh:
- 第一个实例:
JAVA_OPTS="-Xms512m -Xmx1024m -XX:MaxMetaspaceSize=256m" - 第二个实例:
JAVA_OPTS="-Xms256m -Xmx768m -XX:MaxMetaspaceSize=256m"
两个实例的内存总和要控制在物理内存的60%到70%左右,留一部分给操作系统和缓存,查看内存可以用 free -m,确认没有swap占用过高后再调整分配,如果你对单个项目的并发量不确定,宁可先给保守值,运行一段时间观察GC日志再逐步上调。
一台服务器跑两个Tomcat负载均衡配置:Nginx反向代理场景
还有一种常见情况:一台服务器上有两个Tomcat,但它们不是给两个项目用的,而是同一套应用的两个节点,需要做负载均衡,这时候改的东西就不仅仅是端口和环境变量了。
假设Nginx已经装在同一台服务器上,需要在Nginx配置中创建一个upstream组:
upstream backend_tomcats {
server 127.0.0.1:8080 weight=3;
server 127.0.0.1:8081 weight=2;
}
server {
listen 80;
location / {
proxy_pass http://backend_tomcats;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
两个Tomcat的端口已经改好,接下来要注意的是会话保持,负载均衡默认按权重轮询转发请求,同一个用户第一次请求落到8080节点,第二次请求如果被转发到8081节点,而两个Tomcat没有配置session共享,用户就会被强制退出登录,解决办法有两种:

- 在Nginx的upstream中启用
ip_hash,让同一个IP的请求固定转发到同一个Tomcat - 在两个Tomcat之间配置Redis共享session存储,彻底解耦节点状态
从实践角度看,如果两个Tomcat跑的是同一个应用,建议直接使用 ip_hash,改动最小,效果立竿见影,只有当节点需要水平扩展时,再考虑引入Redis session共享。
双Tomcat部署时更容易忽略的三个隐蔽配置项
这三个地方在双Tomcat场景下非常容易漏掉,就算端口、环境变量、JVM都改了,也可能会踩坑:
- 日志目录:第二个Tomcat的logs目录如果沿用默认的相对路径,启动后日志仍然会写到第一个实例的logs下,确认
setenv.sh里加一行export CATALINA_OUT=/usr/local/tomcat2/logs/catalina.out,避免两个实例的catalina.out写到同一个文件。 - 临时目录:两个Tomcat使用同一个临时目录时,上传文件、生成验证码图片可能出现互相覆盖,在
server.xml的<Context>标签中设置workDir,或者在启动脚本中指定java.io.tmpdir。 - JMX监控端口:如果开启了JMX远程监控,两个Tomcat默认的JMX端口也会冲突,需要分别为两个实例配置不同的
com.sun.management.jmxremote.port。
常见问题速查
Q:同一台服务器上的两个Tomcat,第二个启动时提示端口被占用,该怎么排查?
先用 netstat -lnp | grep 8080 确认占用进程,如果是第一个Tomcat占用的,直接修改第二个实例server.xml里的HTTP Connector端口,同时检查shutdown端口和AJP端口是否也冲突,改完重启第二个实例,再用 ss -ltn 确认新端口已监听。
Q:两个Tomcat可以共用一份Tomcat安装目录吗?
可以,但必须正确配置 CATALINA_BASE,共用程序文件、分离实例目录是Tomcat官方支持的部署方式,只需要创建两个独立的conf、logs、webapps、temp目录,然后让两个实例分别通过 CATALINA_BASE 指向各自目录即可。
Q:双Tomcat负载均衡时,Nginx需要修改Tomcat的什么配置吗?
如果使用的是 proxy_pass 反向代理,Tomcat端不需要修改 server.xml 里的地址配置,保持监听端口即可,需要改动的是Nginx的upstream配置,以及两个Tomcat的session存储策略。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/849824.html


评论列表(5条)
这篇文章的内容非常有价值,我从中学习到了很多新的知识和观点。作者的写作风格简洁明了,却又不失深度,让人读起来很舒服。特别是两个部分,给了我很多新的思路。感谢分享这么好的内容!
@雪雪6691:这篇文章的内容非常有价值,我从中学习到了很多新的知识和观点。作者的写作风格简洁明了,却又不失深度,让人读起来很舒服。特别是两个部分,给了我很多新的思路。感谢分享这么好的内容!
这篇文章写得非常好,内容丰富,观点清晰,让我受益匪浅。特别是关于两个的部分,分析得很到位,给了我很多新的启发和思考。感谢作者的精心创作和分享,期待看到更多这样高质量的内容!
这篇文章写得非常好,内容丰富,观点清晰,让我受益匪浅。特别是关于两个的部分,分析得很到位,给了我很多新的启发和思考。感谢作者的精心创作和分享,期待看到更多这样高质量的内容!
读了这篇文章,我深有感触。作者对两个的理解非常深刻,论述也很有逻辑性。内容既有理论深度,又有实践指导意义,确实是一篇值得细细品味的好文章。希望作者能继续创作更多优秀的作品!