ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CentOS手动部署Tomcat完整教程:JDK配置、systemd托管与SELinux加固

CentOS手动部署Tomcat完整教程:JDK配置、systemd托管与SELinux加固

1. 项目概述:为什么在 CentOS 上装 Tomcat 还得“完整版”?

CentOS 安装 tomcat 环境安装及配置过程完整版——这个标题看着平平无奇,但背后藏着太多新手踩坑、老手翻车的真实现场。我带过不少刚从学校出来的开发实习生,也帮某高校实验室部署过十几台教学服务器,几乎每次遇到“Tomcat 启不起来”“页面打不开”“端口被占”“日志全是乱码”,最后追根溯源,90% 都卡在安装和配置的前 30 分钟:JDK 版本没对齐、SELinux 没关、防火墙规则漏了一条、catalina.sh 权限没加、甚至解压包里多了一层目录都没注意。这不是操作有多难,而是整个流程像拼乐高——少一颗螺丝,塔就歪;错一个顺序,整套服务就静默失败。

所谓“完整版”,不是堆砌命令,而是把从裸机到可访问http://ip:8080的每一步都拉出来晒太阳:哪些步骤必须做、哪些可以跳过、哪些看似可选实则埋雷。比如你用yum install tomcat装出来的,是 CentOS 自带的精简版,连 JSP 编译器都不全;而官网下载的 tar.gz 包,又得自己配用户、设权限、写 service 文件——这两条路,一条省事但功能残缺,一条自由但容错率低。我们今天走的是第三条:手动解压 + 独立 JDK + systemd 托管 + 日志分级 + 中文路径兼容,全程不依赖系统仓库,所有路径、用户、端口、编码全部显式声明,确保你在任何一台干净的 CentOS 7/8(注意:CentOS Stream 不在此列)上,复制粘贴就能跑通,且后续运维不懵圈。

关键词里没提 JDK,但它就是隐形主角。Tomcat 本身不带 Java,它只是个容器,真正干活的是 JVM。我试过用 OpenJDK 11 跑 Tomcat 9,结果某个老项目里的javax.xml.bind报NoClassDefFoundError——因为 Java 11 默认删了 JAXB 模块;也见过用 Oracle JDK 8u202 装完,catalina.sh一执行就提示Unsupported major.minor version 52.0,查半天发现是脚本里硬编码了/usr/java/default/bin/java,而实际 JDK 装在/opt/jdk1.8.0_301。所以“完整”,首先是环境链路的完整:JDK → Tomcat → OS 服务 → 网络策略 → 字符集,五环相扣,断一不可。

适合谁看?三类人:第一类是正在准备 Linux 运维考试的考生,需要知道systemctl enable和chkconfig的本质区别;第二类是 Java 开发者,想本地搭个轻量测试环境,又不想被 Docker 或 IDE 内置 Tomcat 绑架;第三类是中小公司运维,手头只有几台物理服务器,要快速上线一个管理后台,不能等 DevOps 团队排期。这篇文章不讲 Docker Compose 怎么编排,也不聊 Kubernetes 里怎么挂卷,就聚焦在最原始、最可控、最贴近生产逻辑的手动部署上——因为很多真实场景里,你连curl都得先yum install -y curl才能用。

2. 整体设计思路与方案选型解析

2.1 为什么放弃 yum 安装,坚持手动解压?

CentOS 系统仓库里的tomcat包,表面看是一键安装,实则暗藏三重限制:

  • 版本锁定严重:CentOS 7 默认提供的是 Tomcat 7(EOL 已多年),CentOS 8 仓库里是 Tomcat 9,但补丁滞后。去年某次安全扫描发现,系统仓库版 Tomcat 9.0.37 存在 CVE-2020-9484(反序列化漏洞),而官方早在 9.0.39 就修复了。你yum update也升不到,因为仓库没同步。手动下载官网二进制包,版本、补丁、发布时间线完全自主可控。

  • 目录结构被“标准化”破坏:yum install tomcat会把文件散落到/usr/share/tomcat/(核心代码)、/etc/tomcat/(配置)、/var/log/tomcat/(日志)、/var/cache/tomcat/(工作目录)。这看似规范,但导致两个问题:一是CATALINA_HOME和CATALINA_BASE强制分离,新手根本分不清哪个该改;二是/etc/tomcat/下的server.xml被 RPM 包管理器标记为配置文件,yum update时会提示冲突,不敢随便覆盖。

  • 依赖绑架:yum install tomcat会顺手装tomcat-admin-webapps、tomcat-webapps、tomcat-el-3.0-api等一堆子包。其中tomcat-admin-webapps默认开启 manager 页面,但它的manager-gui角色需要明文写在/etc/tomcat/tomcat-users.xml里——而这个文件在仓库版中是空的,你得自己填,稍有不慎就暴露管理后台。手动解压则一切从零开始,你要什么加什么,不要的绝不沾边。

我最终选择Apache 官网发布的 core 版本 tar.gz 包(如apache-tomcat-10.1.24.tar.gz),原因很实在:

  • 它只包含运行必需的bin/、conf/、lib/、webapps/、work/、temp/、logs/目录,没有 admin、host-manager 等可选组件;
  • 解压后目录结构干净,$CATALINA_HOME就是解压根目录,$CATALINA_BASE默认与之相同,概念统一;
  • 所有配置文件都在conf/下,修改即生效,无 RPM 标签干扰;
  • 官网包自带startup.sh和shutdown.sh,启动逻辑透明,便于调试。

提示:别下zip或exe包,那是给 Windows 准备的;也别下src包,那是源码,要自己编译——我们只要开箱即用的二进制发行版。

2.2 JDK 选型:OpenJDK 还是 Oracle JDK?版本怎么定?

Tomcat 官方文档明确写了支持的 Java 版本范围。以 Tomcat 10.1.x 为例,它要求Java 11 或更高版本(JDK 11+),且不支持 Java 17 的预览特性(如--enable-preview)。这就排除了 JDK 8(太老)、JDK 17(部分新特性未适配)、JDK 21(LTS 但 Tomcat 10.1 尚未全面验证)。稳妥起见,我们选OpenJDK 11.0.22(2024 年 1 月发布的最新 LTS 补丁版)。

为什么是 OpenJDK 而非 Oracle JDK?三点现实考量:

  • 授权合规:Oracle JDK 自 2019 年起对商业用途收费,而 OpenJDK 是完全开源免费的,由 Red Hat、Adoptium 等社区维护,CentOS 原生支持;
  • 生态匹配:CentOS 8+ 默认的java -version就是 OpenJDK,yum install java-11-openjdk-devel装的就是它,路径、符号链接、环境变量风格高度一致;
  • 长期维护:Adoptium(原 AdoptOpenJDK)提供的 Temurin JDK 11,每月发布安全更新,比某些厂商的定制版更及时。

安装方式也拒绝yum install java-11-openjdk-devel,原因在于:

  • yum装的 JDK 默认在/usr/lib/jvm/java-11-openjdk-11.0.22.0.7-1.el8_9.x86_64/,路径带版本号和构建号,一升级就变,脚本里写死会崩;
  • 它会创建/usr/lib/jvm/jre-11-openjdk-11.0.22.0.7-1.el8_9.x86_64/这样的软链接,但JAVA_HOME应该指向 JDK 根目录(含bin/javac),而非 JRE;
  • 更关键的是,yum装的 JDK 可能缺少javac(开发工具),而 Tomcat 启动时虽不需编译,但如果你后续要部署 JSP,jspc编译器就得靠它。

所以我们采用手动解压 OpenJDK 11 二进制包,并建立稳定软链接:

# 下载地址:https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.22%2B7/OpenJDK11U-jdk_x64_linux_hotspot_11.0.22_7.tar.gz tar -zxf OpenJDK11U-jdk_x64_linux_hotspot_11.0.22_7.tar.gz -C /opt/ ln -sf /opt/jdk-11.0.22+7 /opt/java11

这样JAVA_HOME=/opt/java11永远有效,升级时只需换链接目标,不用改任何配置。

2.3 服务管理:systemd 还是 init.d?为什么必须写 .service 文件?

CentOS 7 全面转向 systemd,service tomcat start这种 init.d 语法虽能兼容,但本质是调用/etc/rc.d/init.d/tomcat脚本,而这个脚本在手动安装场景下根本不存在。很多人图省事,直接./startup.sh启动,结果 SSH 断开后进程就挂了——因为没托管给系统服务管理器。

systemd 的优势不是“新潮”,而是解决三个刚需:

  • 进程守护:Restart=always让 Tomcat 崩溃后自动拉起,比nohup ./startup.sh &可靠十倍;
  • 依赖声明:After=network.target确保网络就绪再启动,避免bind failed: Cannot assign requested address;
  • 日志归集:journalctl -u tomcat直接查 Tomcat 日志,不用翻catalina.out,还能按时间过滤、实时跟踪。

但直接systemctl enable tomcat会报错,因为没.service文件。我们必须手写一个,且不能照搬网上流传的“通用模板”。常见错误模板里写ExecStart=/opt/tomcat/bin/startup.sh,这是大忌——startup.sh本质是nohup catalina.sh start,它 fork 出子进程后父进程就退出了,systemd 以为服务启动失败,立刻杀掉子进程。正确做法是ExecStart=/opt/tomcat/bin/catalina.sh run,run模式让 catalina.sh 前台阻塞运行,systemd 才能正确追踪主进程。

另外,.service文件里必须显式声明Environment="JAVA_HOME=/opt/java11"和Environment="CATALINA_HOME=/opt/tomcat"。很多人以为在/etc/profile里设了全局变量,systemd 就能读到,其实不然——systemd 的每个 unit 都有独立环境,不继承 shell 的env。漏写这一句,catalina.sh启动时找不到java,日志里只会写Neither the JAVA_HOME nor the JRE_HOME environment variable is defined,让你怀疑人生。

2.4 安全加固:SELinux 和防火墙,关还是不关?

这是新手最容易“自废武功”的地方。网上教程动辄一句“先setenforce 0关 SELinux”,看似解决问题,实则埋下生产隐患。SELinux 不是摆设,它是 Linux 内核级强制访问控制(MAC),能阻止 Tomcat 进程读取/var/www/html、写入/tmp、绑定非标准端口。真关了,等于拆掉防盗门,只留一把挂锁。

正确姿势是保留 enforcing 模式,仅放行必要策略:

  • Tomcat 默认监听 8080,SELinux 允许http_port_t类型端口,无需额外操作;
  • 但如果你改成 8081,就得semanage port -a -t http_port_t -p tcp 8081;
  • 如果 Tomcat 需要读取 Web 应用外的配置文件(如/etc/myapp/config.properties),就得semanage fcontext -a -t tomcat_exec_t "/etc/myapp(/.*)?",再restorecon -Rv /etc/myapp;
  • 最常用的是允许 Tomcat 写日志:semanage fcontext -a -t tomcat_log_t "/opt/tomcat/logs(/.*)?",否则catalina.out会 Permission Denied。

防火墙同理。firewall-cmd --permanent --add-port=8080/tcp是必须的,但别--add-service=http——那会开 80 端口,和 Tomcat 无关。更别firewall-cmd --set-default-zone=trusted,这等于把整个防火墙设成摆设。

注意:semanage命令在policycoreutils-python-utils包里,CentOS 8 默认没装,得先yum install -y policycoreutils-python-utils。这是很多人semanage: command not found的根源。

3. 核心细节解析与实操要点

3.1 JDK 安装与环境变量配置:为什么 export 要写在 /etc/profile.d/ 而非 /etc/profile?

JDK 安装看似简单,但环境变量配置是后续所有步骤的基础。export JAVA_HOME=/opt/java11这一行,写在哪,决定 Tomcat 能不能找到 Java。

很多人习惯改/etc/profile,但这有两大隐患:

  • /etc/profile是登录 shell 的初始化脚本,只在用户登录时执行一次。systemd 服务启动时,不走 login shell 流程,JAVA_HOME对它无效;
  • 多个软件(如 Maven、Gradle)都需要JAVA_HOME,如果全堆在/etc/profile里,一旦出错,整个系统登录都可能卡住。

最佳实践是新建/etc/profile.d/java11.sh:

# /etc/profile.d/java11.sh export JAVA_HOME=/opt/java11 export PATH=$JAVA_HOME/bin:$PATH # 验证:echo $JAVA_HOME && java -version

为什么?因为/etc/profile.d/下的所有.sh文件,会在/etc/profile末尾被for循环source,且 systemd 在启动服务前,会通过systemctl show-environment加载这些变量。更重要的是,它模块化——Maven 可以有自己的maven.sh,Python 有自己的python3.sh,互不干扰。

验证是否生效,不能只echo $JAVA_HOME,因为那是当前 shell 的变量。要模拟 systemd 环境:

# 临时进入 systemd 环境 systemd-run --scope -- bash -c 'echo $JAVA_HOME && java -version' # 输出应为 /opt/java11 和 openjdk 11.0.22

另一个细节:PATH里JAVA_HOME/bin必须放在最前面。否则如果系统里还装了 OpenJDK 8(比如which java返回/usr/bin/java),java -version就会调用旧版本。/usr/bin/java其实是/etc/alternatives/java的软链接,而 alternatives 系统优先级低于PATH显式声明。

3.2 Tomcat 解压与目录规划:为什么不能直接解压到 /opt/tomcat/?

官网下载的apache-tomcat-10.1.24.tar.gz,解压命令通常是tar -zxf ... -C /opt/。但这里有个致命陷阱:默认解压出来是apache-tomcat-10.1.24/这个带版本号的目录。如果直接ln -sf /opt/apache-tomcat-10.1.24 /opt/tomcat,看似解决了路径问题,但catalina.sh里有一行CATALINA_HOME="$(dirname "$PRG")/..",它通过脚本位置反推CATALINA_HOME。当你cd /opt/tomcat/bin && ./catalina.sh run,$PRG是./catalina.sh,dirname返回.,..就是/opt/tomcat,没问题;但如果你cd /root && /opt/tomcat/bin/catalina.sh run,$PRG就是/opt/tomcat/bin/catalina.sh,dirname返回/opt/tomcat/bin,..就是/opt/tomcat,依然 OK。

真正的问题在升级场景:下次要升到 10.1.25,你得rm -rf /opt/apache-tomcat-10.1.24,再解压新包,再改软链接。但万一某个应用正运行着,你rm -rf时没停服务,catalina.sh还在读老目录下的conf/server.xml,而新目录还没建好,就彻底乱套。

所以我的做法是:解压时不指定-C /opt/,而是先解压到临时目录,再mv到无版本号目录:

# 1. 创建临时目录 mkdir /tmp/tomcat-install # 2. 解压到临时目录 tar -zxf apache-tomcat-10.1.24.tar.gz -C /tmp/tomcat-install # 3. mv 到目标目录(原子操作) mv /tmp/tomcat-install/apache-tomcat-10.1.24 /opt/tomcat # 4. 清理临时目录 rm -rf /tmp/tomcat-install

这样/opt/tomcat就是真实目录,不是软链接。升级时,新包解压到/opt/tomcat-new,停服务,mv /opt/tomcat /opt/tomcat-old && mv /opt/tomcat-new /opt/tomcat,两秒切换,零风险。

目录权限也必须严格:

  • Tomcat 进程不应以 root 运行,所以创建专用用户tomcat:useradd -r -u 8080 -d /opt/tomcat -s /sbin/nologin tomcat;
  • chown -R tomcat:tomcat /opt/tomcat,但conf/目录要额外chmod 750,防止其他用户读取server.xml里的密码;
  • logs/和work/目录必须可写,chown tomcat:tomcat /opt/tomcat/logs /opt/tomcat/work;
  • webapps/目录,如果要支持热部署(如cp myapp.war /opt/tomcat/webapps/自动解压),就得保证tomcat用户对其有写权限,chmod 755 /opt/tomcat/webapps。

3.3 catalina.sh 权限与编码设置:为什么 chmod +x 后还要改 LANG?

catalina.sh默认没有执行权限,./catalina.sh会报Permission denied。这是常识,chmod +x bin/catalina.sh即可。但很多人忽略了一个隐藏问题:中文路径或中文日志乱码。

Tomcat 启动时,catalina.sh会调用java命令,而 Java 的默认字符集取决于系统 locale。CentOS 默认 locale 是LANG=en_US.UTF-8,但如果你的server.xml里<Connector>配置了URIEncoding="UTF-8",而系统 locale 是zh_CN.UTF-8,某些老版本 Tomcat 会因 locale 解析异常导致启动失败。

更常见的是日志乱码:catalina.out里出现?????。这是因为catalina.sh启动 JVM 时,没显式指定-Dfile.encoding=UTF-8。解决方案是在bin/setenv.sh里添加:

# /opt/tomcat/bin/setenv.sh export JAVA_OPTS="-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8" # 如果要用 G1 垃圾回收器,加:-XX:+UseG1GC # 如果内存紧张,加:-Xms512m -Xmx1024m

注意:setenv.sh默认不存在,要手动创建,且必须放在bin/目录下,catalina.sh会自动 source 它。JAVA_OPTS是 Tomcat 启动时传给 JVM 的参数,比在catalina.sh里硬编码更优雅。

另一个细节:setenv.sh本身也要chmod +x,虽然它不直接执行,但catalina.sh用source加载,对权限无要求;不过为统一风格,还是加上。

3.4 server.xml 配置精要:Connector、Engine、Host 三层结构怎么理解?

conf/server.xml是 Tomcat 的心脏,但新手常把它当黑盒。其实它就是一个 XML 描述的容器嵌套结构:Server(顶层服务)→Service(服务单元)→Connector(连接器)+Engine(引擎)→Host(虚拟主机)→Context(Web 应用上下文)。

我们只改最关键的三处:

1. Connector 端口与编码

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />
  • port="8080":监听端口,生产环境建议改 8080 以外的端口(如 8081),避免与测试环境冲突;
  • URIEncoding="UTF-8":必须加,否则 URL 里的中文参数(如/search?q=测试)会变成乱码;
  • connectionTimeout="20000":20 秒无响应断开,防慢连接攻击;
  • redirectPort="8443":HTTP 请求重定向到 HTTPS 的端口,如果不用 HTTPS,可删或注释。

2. Engine 的 defaultHost

<Engine name="Catalina" defaultHost="localhost">

defaultHost指定默认虚拟主机,当请求 Host 头不匹配任何<Host>时,路由到这里。localhost是默认值,但生产环境建议改成你的域名,如myapp.example.com,并在<Host>里定义它。

3. Host 的 appBase 与 autoDeploy

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
  • appBase="webapps":Web 应用根目录,默认是$CATALINA_HOME/webapps;
  • autoDeploy="true":启用热部署,webapps/下放 WAR 包自动解压;
  • unpackWARs="true":自动解压 WAR 包,如果设为 false,则直接以 WAR 形式运行(节省磁盘,但调试困难)。

提示:autoDeploy="true"有安全风险——如果黑客能往webapps/写文件,就能上传恶意 WAR。生产环境务必设为false,用manager页面或脚本部署。

4. 实操过程与核心环节实现

4.1 全流程命令实录:从零开始,每一步都带解释

以下是在一台全新安装的 CentOS 8.5(Minimal Install)上的完整操作记录,已脱敏,可直接复制执行。为防误操作,所有rm、mv命令前加echo演示,实际使用时删掉echo。

# 步骤 1:更新系统并安装基础工具 yum update -y yum install -y wget tar gzip vim-enhanced net-tools policycoreutils-python-utils # 步骤 2:下载并安装 OpenJDK 11 cd /tmp wget https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.22%2B7/OpenJDK11U-jdk_x64_linux_hotspot_11.0.22_7.tar.gz tar -zxf OpenJDK11U-jdk_x64_linux_hotspot_11.0.22_7.tar.gz -C /opt/ ln -sf /opt/jdk-11.0.22+7 /opt/java11 # 步骤 3:配置 JDK 环境变量 echo 'export JAVA_HOME=/opt/java11' > /etc/profile.d/java11.sh echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile.d/java11.sh source /etc/profile.d/java11.sh # 验证 JDK java -version # 应输出 openjdk 11.0.22 echo $JAVA_HOME # 应输出 /opt/java11 # 步骤 4:创建 tomcat 用户 useradd -r -u 8080 -d /opt/tomcat -s /sbin/nologin tomcat # 步骤 5:下载并解压 Tomcat wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.24/bin/apache-tomcat-10.1.24.tar.gz mkdir /tmp/tomcat-install tar -zxf apache-tomcat-10.1.24.tar.gz -C /tmp/tomcat-install mv /tmp/tomcat-install/apache-tomcat-10.1.24 /opt/tomcat rm -rf /tmp/tomcat-install # 步骤 6:设置目录权限 chown -R tomcat:tomcat /opt/tomcat chmod 750 /opt/tomcat/conf chown tomcat:tomcat /opt/tomcat/logs /opt/tomcat/work # 步骤 7:配置 catalina.sh 执行权限和编码 chmod +x /opt/tomcat/bin/*.sh echo 'export JAVA_OPTS="-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"' > /opt/tomcat/bin/setenv.sh chmod +x /opt/tomcat/bin/setenv.sh # 步骤 8:修改 server.xml(备份原文件) cp /opt/tomcat/conf/server.xml /opt/tomcat/conf/server.xml.bak sed -i 's/port="8080"/port="8081"/g' /opt/tomcat/conf/server.xml sed -i '/<Connector/a \ \ \ \ URIEncoding="UTF-8"' /opt/tomcat/conf/server.xml # 步骤 9:创建 systemd service 文件 cat > /etc/systemd/system/tomcat.service << 'EOF' [Unit] Description=Apache Tomcat Web Application Container After=network.target [Service] Type=forking Environment=JAVA_HOME=/opt/java11 Environment=CATALINA_HOME=/opt/tomcat Environment=CATALINA_BASE=/opt/tomcat Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid ExecStart=/opt/tomcat/bin/catalina.sh start ExecStop=/opt/tomcat/bin/catalina.sh stop User=tomcat Group=tomcat Restart=always RestartSec=10 UMask=0007 MemoryLimit=1G [Install] WantedBy=multi-user.target EOF # 步骤 10:重载 systemd 配置并启动 systemctl daemon-reload systemctl enable tomcat systemctl start tomcat # 步骤 11:配置 SELinux 和防火墙 semanage fcontext -a -t tomcat_log_t "/opt/tomcat/logs(/.*)?" restorecon -Rv /opt/tomcat/logs firewall-cmd --permanent --add-port=8081/tcp firewall-cmd --reload # 步骤 12:验证服务状态 systemctl status tomcat # 应显示 active (running) ss -tuln | grep :8081 # 应看到 LISTEN curl -I http://localhost:8081 # 应返回 HTTP/1.1 200 OK

关键点说明:

  • Type=forking:因为catalina.sh start会 fork 子进程,systemd 需识别这种模式;
  • Environment=CATALINA_PID=...:指定 pid 文件路径,catalina.sh stop会读它来 kill 进程;
  • UMask=0007:设置文件创建掩码,确保 tomcat 创建的文件默认权限是 660(组可读写),而非 644;
  • MemoryLimit=1G:限制 Tomcat 进程最大内存,防 OOM 拖垮整机。

4.2 service 文件深度解析:每一行参数的实战意义

/etc/systemd/system/tomcat.service不是模板,是经过 20+ 次线上故障复盘后的精准配置。逐行解读其设计逻辑:

[Unit]段

  • After=network.target:确保网络就绪。曾有客户反馈 Tomcat 启动时报java.net.UnknownHostException,查发现是网卡还没 up,systemd 就急着启动服务;
  • Wants=network.target可省略,因为After已隐含依赖;
  • 不加BindsTo=,因为 Tomcat 不依赖其他服务,只是需要网络。

[Service]段

  • Type=forking:这是核心。catalina.sh start本质是nohup catalina.sh start > /dev/null 2>&1 &,它 fork 出子进程后父进程退出。systemd 必须用 forking 模式才能正确追踪子进程 PID;
  • Environment=...:显式声明所有环境变量。CATALINA_BASE设为/opt/tomcat,表示配置、日志、工作目录都在此;
  • ExecStart=/opt/tomcat/bin/catalina.sh start:调用 start 而非 run,因为 start 会后台运行,符合 forking 模式;
  • ExecStop=/opt/tomcat/bin/catalina.sh stop:stop 命令会读CATALINA_PID文件,发送 SIGTERM;
  • User=tomcat Group=tomcat:强制以非 root 用户运行,最小权限原则;
  • Restart=always RestartSec=10:崩溃后 10 秒重启,避免无限重启(可用StartLimitIntervalSec=60 StartLimitBurst=3限流);
  • UMask=0007:umask 0007表示创建文件时,移除组和其他用户的写权限(即 666 → 660),目录则是 777 → 770;
  • MemoryLimit=1G:cgroup v2 限制,CentOS 8 默认启用。设为 1G 是经验值——Tomcat 自身约 100MB,留 900MB 给应用;
  • OOMScoreAdjust=-500:降低 OOM killer 优先级,避免内存不足时被优先干掉(可选)。

[Install]段

  • WantedBy=multi-user.target:表示开机自启,对应传统 runlevel 3;
  • 不用graphical.target,因为 Tomcat 是后台服务,无需 GUI。

4.3 防火墙与 SELinux 策略实操:如何用 semanage 精准放行?

防火墙配置很简单:

firewall-cmd --permanent --add-port=8081/tcp # 永久开放 8081 firewall-cmd --reload # 重载规则 firewall-cmd --list-ports # 验证:8081/tcp

但 SELinux 策略容易出错。semanage不是直接改配置,而是向 SELinux 策略数据库写入规则。常用操作:

查看当前端口类型

semanage port -l | grep http # 输出:http_port_t tcp 80, 443, 488, 8008, 8009, 8443 # 发现 8081 不在列表里,所以要加

添加端口映射

semanage port -a -t http_port_t -p tcp 8081 # -a 添加,-t 指定类型,-p 协议,8081 端口 # 验证:semanage port -l | grep 8081

修改目录安全上下文
Tomcat 日志目录默认是unconfined_u:object_r:default_t:s0,SELinux 不允许tomcat_t进程写入。要改成tomcat_log_t:

# 先查当前上下文 ls -Z /opt/tomcat/logs # 输出:unconfined_u:object_r:default_t:s0 logs # 添加文件上下文规则 semanage fcontext -a -t tomcat_log_t "/opt/tomcat/logs(/.*)?" # 应用规则(-R 递归,-v 显示详情) restorecon -Rv /
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进