在單台伺服器上運行多個 Tomcat 實例,核心在於端口隔離與環境變數獨立。每個實例需擁有獨立的 server.xml(修改 HTTP/Shutdown/AJP 端口)、catalina.sh/bat(設定 CATALINA_BASE 與 JAVA_HOME)以及獨立的 webapps、logs、work、temp 目錄。本文以 Windows 環境為例,記錄實戰遇到的 WAR 不解壓、無法訪問等經典坑點與解決方案。
server.xml)打開 conf/server.xml,修改以下三個關鍵端口,確保各實例互不衝突:
<!-- 1. 關閉端口(預設 8005)-->
<Server port="8006" shutdown="SHUTDOWN">
<!-- 2. HTTP 連接器端口(預設 8080)-->
<Connector port="8081"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- 3. AJP 端口(預設 8009,若前端接 Nginx/Apache 需修改)-->
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />
原則:第二個實例端口號建議在預設基礎上 +1 或 +100,例如 8006/8081/8010;第三個實例再遞增。
unpackWARs)預設 Tomcat 會自動解壓 webapps 目錄下的 .war 檔案。若發現 WAR 不解壓,檢查 server.xml 中 <Host> 元素:
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- ... -->
</Host>
unpackWARs="true":啟用自動解壓。autoDeploy="true":啟用熱部署(運行期間放入 WAR 自動部署)。若配置無誤但仍不解壓,多半是啟動腳本缺少 JDK 環境變數(見下節)。
JAVA_HOME 與 CATALINA_HOMEwebapps 下手動放入編譯好的專案目錄,瀏覽器訪問 404。Windows 下 bin/startup.bat 若未顯式設定 JAVA_HOME,會嘗試從註冊表尋找 JRE,導致類別路徑錯誤,核心類別無法載入,進而影響部署器運作。
bin/startup.bat(或 catalina.bat)檔案開頭@echo off REM === 必須在最前面設定 === SET JAVA_HOME=C:\Program Files\Java\jdk1.8.0_202 SET CATALINA_HOME=E:\apache-tomcat-9.0.70-instance2 REM === 也可設定 CATALINA_BASE 若採用分離部署 === REM SET CATALINA_BASE=E:\tomcat-instances\instance2 REM 原有內容保持不變 call "%EXECUTABLE%" start %CMD_LINE_ARGS%
注意:路徑含空格時需用雙引號包裹,或使用短路徑(PROGRA~1)。修改後重新執行 startup.bat,觀察控制台輸出 org.apache.catalina.startup.Catalina.start Server startup in xxx ms 即成功。
CATALINA_BASE 分離配置與二進制(推薦生產環境)官方推薦一份二進制、多份基礎目錄模式:
CATALINA_HOME)。CATALINA_BASE 目錄結構:instance-a/
├── conf/ # server.xml, web.xml, context.xml 等獨立配置
├── logs/ # 獨立日誌
├── webapps/ # 獨立應用部署目錄
├── work/ # JSP 編譯臨時目錄
├── temp/ # 臨時檔案目錄
└── bin/
├── setenv.sh/bat # 實例專屬 JVM 參數、JAVA_HOME
└── startup.sh/bat # 可選,繼承 CATALINA_HOME/bin 的啟動邏輯
# Linux/Mac export CATALINA_BASE=/opt/tomcat-instances/instance-a $CATALINA_HOME/bin/startup.sh # Windows SET CATALINA_BASE=E:\tomcat-instances\instance-a %CATALINA_HOME%\bin\startup.bat
優勢:核心升級只需替換 CATALINA_HOME,各實例配置完全隔離,維護成本極低。
| 現象 | 可能原因 | 排查步驟 |
|---|---|---|
| 端口衝突啟動失敗 | 多實例端口未修改或被其他程序佔用 | netstat -ano | findstr :8081 查找 PID,修改 server.xml 或釋放端口 |
| WAR 不解壓、目錄部署 404 | JAVA_HOME 未設、unpackWARs=false、appBase 路徑錯誤 | 檢查 startup.bat 環境變數、server.xml Host 配置、webapps 目錄權限 |
| 中文亂碼 | Connector 缺少 URIEncoding="UTF-8" | 在 <Connector> 加入 URIEncoding="UTF-8" useBodyEncodingForURI="true" |
| 記憶體溢出 (OOM) | JVM 堆內存不足 | 在 setenv.sh/bat 設定 JAVA_OPTS="-Xms512m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m" |
| Session 丟失(集群) | 未配置 Session 複製或黏性 Session | 啟用 <Cluster> 或 Nginx ip_hash、Redis 共享 Session |
# /etc/systemd/system/tomcat-instance2.service [Unit] Description=Apache Tomcat Instance 2 After=network.target [Service] Type=forking Environment=CATALINA_HOME=/opt/tomcat Environment=CATALINA_BASE=/opt/tomcat-instances/instance2 Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk Environment=CATALINA_PID=/opt/tomcat-instances/instance2/tomcat.pid ExecStart=/opt/tomcat/bin/startup.sh ExecStop=/opt/tomcat/bin/shutdown.sh User=tomcat Group=tomcat Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target
啟用:systemctl daemon-reload && systemctl enable --now tomcat-instance2
startup.bat/sh 頭部必設 JAVA_HOME、CATALINA_HOME/Base。按上述步驟操作,即可在單台伺服器穩定運行多個互不干擾的 Tomcat 實例,滿足多專案、多環境部署需求。