Tomcat开篇

6464 字
32 分钟
Tomcat开篇

Tomcat开篇#

[TOC]


初认知#

🌟 为什么 Java 需要 JVM(Java 虚拟机)?

想象一下:

  • C语言:写好代码后,想要分别运行在 Windows、Linux、Mac
    • 就得重新编译一次(每换一个系统)、==移植性差==
  • Java:你只编译一次,生成的是 字节码(.class 文件)
    • JVM 看的“中间语言”

JVM 就像一个“翻译官”:它安装在不同操作系统上

  • 负责把统一的 Java 字节码“实时翻译”成当前系统能执行的机器指令
    • ==“一次编译,到处运行”==

图片变清晰
图片变清晰

  • JRE → 是 运行 Java 程序 所需的最小环境 → 包含:JVM + Java 核心类库普通用户 只需要安装 JRE 就能运行 .jar 或其他 Java 应用
  • JDK → 是 开发 Java 程序 必备的工具包 → 包含:JRE( JVM + 类库) + 开发工具开发者必须安装 JDK,因为你要写代码、编译成 .class 文件

🌐 Nginx vs Tomcat —— Web 服务器的区别

NginxTomcat
类型高性能 Web 服务器 / 反向代理Web 容器
主要用途处理静态资源(HTML、CSS、JS、图片) 负载均衡、反向代理运行 Java Web 应用(Servlet、JSP、Spring Boot 等)
静态资源✅ 极快、高并发✅ 支持,但性能不如 Nginx
动态内容❌ 不能直接运行 Java 代码✅ 专为 Java 动态 Web 应用设计
实际用法常作为 前端代理,把动态请求转发给 Tomcat专注处理 Java 业务逻辑
角色职责类比
Nginx前台接待+保安+分流员先找它,静态文件直接给;如果是 Java 请求,就转交给后端 Tomcat
Tomcat后台程序员专心处理业务逻辑(比如登录、下单、查数据库),返回动态结果

🛠️ 典型架构: 用户 → Nginx(处理静态文件 + 负载均衡) → Tomcat(处理 Java 接口,返回动态结果)


🧃 JAR 包 —— “普通 Java 程序的打包方式”

  • 就像一个“可执行的压缩包”
    • 命令行一敲,程序就跑起来了!
    • Spring Boot 默认打成的也是 JAR(因为它内嵌了 Tomcat)

✅ 一句话:JAR 是“独立运行”的 Java 程序包

🌐 WAR 包 —— “专门给 Web 服务器用的 Java 程序包”

  • 专为 Web 应用设计

  • 它不能自己跑!必须“寄宿”在 Web 容器里,比如 Tomcat

  • 怎么运行?

    • myweb.war 文件扔进 Tomcat 的 webapps/ 目录
    • 启动 Tomcat —》自动解压它

✅ 一句话:WAR 是“需要 Tomcat 这种 Web 服务器才能跑”的网站/接口包

🥤 对比总结(超简单版)

JAR 包WAR 包
能不能直接运行?✅ 能!java -jar xxx.jar❌ 不能!必须放到 Tomcat 里
用来干啥?普通程序、后台服务、Spring Boot 应用传统的 Java Web 项目(Servlet/JSP)
访问方式?命令行启动,可能没网页通过浏览器访问 http://...
包含Web资源?是(JSP、HTML等)
谁负责运行?JVMTomcat(或其他 Web 容器)

部署Tomcat#

Tomcat 版本最低 JDK 要求推荐 JDK 版本
Tomcat 11JDK 17JDK 17+
Tomcat 10.xJDK 8(但部分功能需 JDK 11)JDK 11+
Tomcat 9.xJDK 8JDK 8 或 JDK 11
场景推荐 JDK
老项目、传统系统、追求稳定✅ JDK 8(最经典,兼容性最好)
想用新点的 JDK(如 LTS 版本),且无特殊依赖✅ JDK 11(也是 LTS,性能更好)

image-20260323095601243
image-20260323095601243

Terminal window
'web01部署JDK'
[root@web01 ~]# cd /server/tmp/
[root@web01 tmp]# rz
# 上传JDK8安装
[root@web01 tmp]# ll jdk-8u181-linux-x64.rpm
-rw-r--r-- 1 root root 170023183 Dec 31 20:53 jdk-8u181-linux-x64.rpm
[root@web01 tmp]# rpm -ivh jdk-8u181-linux-x64.rpm
[root@web01 tmp]# rpm -qa|grep jdk
jdk1.8-1.8.0_181-fcs.x86_64
# 检查
[root@web01 tmp]# java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
# 成功安装!
[root@web01 tmp]# rz
# 上传tomcat
'下载Tomcat9'当然也能通过wget下载
# 复制下载链接🔗
[root@web01 tmp]# ll apache-tomcat-9.0.113.tar.gz
-rw-r--r-- 1 root root 13049663 Dec 31 20:52 apache-tomcat-9.0.113.tar.gz
'企业中解压即用的包、经常放的位置(1.自定义目录 2./usr/local)'
[root@web01 tmp]# mkdir /soft
[root@web01 tmp]# tar xf apache-tomcat-9.0.113.tar.gz -C /soft/
# 解压到/soft
[root@web01 tmp]# ll /soft/
total 0
drwxr-xr-x 9 root root 220 Mar 23 10:32 apache-tomcat-9.0.113
[root@web01 soft]# ln -s /soft/apache-tomcat-9.0.113/ /soft/tomcat
[root@web01 soft]# ll /soft/
total 0
drwxr-xr-x 9 root root 220 Mar 23 10:32 apache-tomcat-9.0.113
lrwxrwxrwx 1 root root 28 Mar 23 14:14 tomcat -> /soft/apache-tomcat-9.0.113/
# 第二个是软连接
====================================
# tomcat软件目录结构:
bin ---主要包含启动和关闭tomcat的脚本(启停java脚本依赖jar包文件)
conf ---tomcat配置文件的目录(站点配置:server.xml)
lib ---tomcat运行时需要加载的jar包
logs ---tomcat日志存放位置
temp ---tomcat临时存放文件路径
webapps ---tomcat默认站点目录
work ---tomcat运行时产生的缓存文件
====================================
# 运行Tomcat
[root@web01 soft]# cd tomcat/bin
[root@web01 bin]# ls
startup.sh shutdown.sh
'主要是这俩进行控制启停!'
# 里面还有一些是以.bat结尾的文件-->Win启停!
[root@web01 bin]# startup.sh
-bash: startup.sh: command not found
'必须要以./开头!当前路径下!'
[root@web01 bin]# ./startup.sh
# 相对路径启动Tomcat
Using CATALINA_BASE: /soft/tomcat
...
Tomcat started.
[root@web01 ~]# /soft/tomcat/bin/startup.sh
Tomcat started.
# 绝对路径启动Tomcat
[root@web01 ~]# ss -lntup |grep 8080
# 默认运行端口8080
tcp LISTEN .. *:8080 (("java",pid=1679,fd=58))
浏览器测试访问!

image-20260323144340225
image-20260323144340225

systemd启动#

Terminal window
# 这里我们把配置文件放在了
'/usr/lib/systemd/system/' --> 系统默认配置
# 但这里我觉得放在/etc/systemd/system/也是行的通的!
[root@web01 ~]# vim /usr/lib/systemd/system/tomcat.service
[Unit]
Description=Apache Tomcat Server
# 服务描述
After=network.target remote-fs.target nss-lookup.target
# 启动顺序(此服务在指定目标之后启动),要有网络...
[Service]
Type=forking
# 守护进程的方式运行!
ExecStart=/soft/tomcat/bin/startup.sh
ExecStop=/soft/tomcat/bin/shutdown.sh
# 分别对应启动,停止,重启
'systemd 中没有 ExecRestart 这个指令。这是无效的配置项'
# 当你运行 systemctl restart tomcat 时,systemd 会:先stop在start
# 脚本要给执行权限+x,service文件不需要给!
[Install]
WantedBy=multi-user.target
# 在多用户的运行级别下,启动
[root@web01 ~]# ll /usr/lib/systemd/system/tomcat.service
-rw-r--r-- 1 root root 320 Mar 23 14:47 /usr/lib/systemd/system/tomcat.service
[root@web01 ~]# systemctl daemon-reload
# 重新加载systemctl
[root@web01 ~]# systemctl restart tomcat
'Tomcat默认不支持“热重载reload”,它的“重启”通常是完整stop + start'
[root@web01 ~]# systemctl status tomcat
tomcat.service - Apache Tomcat Server
Loaded: loaded (/usr/lib/systemd/system/tomcat.service; disabled; vendor preset: disabled)
Active: active (running) since Mon 2026-03-23 15:13:01 CST; 2s ago
Main PID: 2287 (java)
Tasks: 28
Memory: 73.6M
CGroup: /system.slice/tomcat.service
└─2287 /usr/bin/java
Mar 23 15:13:00 web01 systemd[1]: Starting Apache Tomcat Server...
Mar 23 15:13:01 web01 startup.sh[2273]: Tomcat started.
Mar 23 15:13:01 web01 systemd[1]: Started Apache Tomcat Server.
# 成功启动!
[root@web01 ~]# ss -lntup |grep 8080
tcp LISTEN *:8080 (("java",pid=2287,fd=58))
====================================
# Nginx启停方式两种
1.systemctl start nginx
systemctl stop nginx
systemctl restart nginx
systemctl reload nginx
systemctl status nginx
systemctl enable nginx
systemctl disable nginx
2.使用命令运行
'如果编译安装,就要用这种方式启停!'
/usr/sbin/nginx # 启动
/usr/sbin/nginx -s stop # 停止
/usr/sbin/nginx -s reload # 重新加载
# 同一时间通常用一种方式来管理启动方式
# 要么是用命令、要么是用systemd

主配置文件#

Terminal window
[root@web01 ~]# cd /soft/tomcat/conf/
[root@web01 conf]# ls
Catalina ...web.xml ...context.xml server.xml
[root@web01 conf]# cat server.xml
整体结构说明
server.xml 采用嵌套结构,从外到内定义了 Tomcat 的运行时容器:
Server -> Service -> Connector(s) + Engine -> Host -> Context
Tomcat 结构Nginx 类比作用说明
<Server>整个 Nginx 进程代表一个 Tomcat 实例(一个 JVM 进程),一般不用改
<Service>http { }把一组 Connector 和 Engine 绑定在一起,通常只有一个,也不常改
<Connector>listen 指令监听端口(如 8080),相当于 Nginx 的 listen 80;,经常要改(比如改端口、加 HTTPS)
<Engine>所有 server {} 的集合处理请求的引擎,一般不动
<Host>server { }虚拟主机,对应一个域名或 IP,经常要改(比如改 appBase 指定 Web 应用目录)
<Context>(可选)location /xxx { }单个 Web 应用的上下文路径(URL 路径映射),但通常不直接写在 server.xml
Terminal window
<?xml version="1.0" encoding="UTF-8"?>
✅<Server port="8005" shutdown="SHUTDOWN">
# Tomcat 的 关闭(Shutdown)端口
'Tomcat 启动后,会额外监听一个 TCP 端口(默认 8005),专门用来接收“关闭指令”'
...
<GlobalNamingResources>
# 全局共享资源的声明
📌 类比:就像公司有一个“公共资源登记处”,各个部门(Web 应用)可以去那里领用统一配发的工具
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
... />
</GlobalNamingResources>
✅<Service name="Catalina">
# Tomcat 架构中的一个核心“模块”
# 一组 Connector 和 Engine 绑定在一起,通常只有一个
# 💡 记住:<Service> = “耳朵(Connector) + 大脑(Engine)” 的组合体
🐴 <Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxParameterCount="1000"
/>🐴
# 端口号,协议,超时时间...
✅<Engine name="Catalina" defaultHost="localhost">
# 处理请求的引擎,一般不动
# 这里还有默认的首页
🐴<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
# 这块就是我们的主机了
# appBase --》代码目录
# unpackWARs --》自动解压war包
# autoDeploy --》自动部署
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
# 指定日志还有格式!
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>🐴
</Engine>✅
</Service>✅
</Server>✅
[root@web01 conf]# cp server.xml server.xml.back
# 改配置文件之前先进行备份!
[root@web01 conf]# ll server*
-rw------- 1 root root 8022 Dec 3 03:51 server.xml
-rw------- 1 root root 8022 Mar 23 16:37 server.xml.back
====================================
'把一些注释啥的都删除掉!'
<!-- 注释 -->
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxParameterCount="1000"
/>
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
</Engine>
</Service>
</Server>

快速部署#

Host#

Terminal window
cd /soft/tomcat/conf/
[root@web01 conf]# vim server.xml
...
<!--复制一份Host自定义为diy.kpyun.com 代码目录指向/code/diy-->
<Host name="diy.kpyun.com" appBase="/code/diy/"
unpackWARs="true" autoDeploy="true">
<!--修改了域名和代码目录-->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="diy.kpyun.com" suffix=".log"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
<!--日志修改了位置和后缀-->
</Engine>
</Service>
</Server>
====================================
'重新开一个窗口'
[root@web01 ~]# cd /soft/tomcat/logs/
[root@web01 logs]# ls
...
localhost_access_log.2026-03-23.txt
catalina.out
[root@web01 logs]# tail -f catalina.out
# 拉到一个空白的区域!
====================================
'回到另一个窗口!'
[root@web01 conf]# systemctl restart tomcat
# 重启生效
====================================
'看日志!'
Starting ProtocolHandler ["http-nio-8080"]
# 协议处理器成功启动
Server startup in [508] milliseconds
# 这是 Tomcat 启动成功的标志性日志!
====================================
Tomcat 会自动创建 appBase 目录吗?
会!
[root@web01 conf]# ll -d /code/diy/
drwxr-x--- 2 root root 6 Mar 23 17:03 /code/diy/
# 我原本并没有这个目录!
'在启动时,Tomcat 检查 appBase 路径是否存在:'
📌如果 不存在 自动创建(前提是 Tomcat 进程有该路径的写权限)
✅因为 Tomcat 进程是以 root 用户启动,所以它会以root身份创建
====================================
[root@web01 conf]# echo diy... > /code/diy/index.html
[root@web01 conf]# grep diy.kpyun.com /etc/hosts
10.0.0.7 diy.kpyun.com
'本地hosts解析'
[root@web01 conf]# curl diy.kpyun.com:8080
HTTP Status 404 Not Found
'找不到页面!'
[root@web01 conf]# mkdir /code/diy/ROOT
# 我们还必须要创建一个ROOT目录
'得有一个大写的ROOT'
[root@web01 conf]# mv /code/diy/index.html /code/diy/ROOT/
[root@web01 conf]# ll /code/diy/ROOT/
total 4
-rw-r--r-- 1 root root 7 Mar 23 17:27 index.html
[root@web01 conf]# curl diy.kpyun.com:8080
diy...
'成功拉取到!'

关键词通俗解释#

💡举个完整例子

  • 你有域名:diy.kpyun.com
  • 你想让用户访问 http://diy.kpyun.com/admin 时,看到 /opt/admin/ 里的内容
<Host name="diy.kpyun.com" appBase="/code/diy"
unpackWARs="true" autoDeploy="true">
<Context path="/admin" docBase="/opt/admin" reloadable="true" />
</Host>

==要求:==

  • /code/diy 存在(哪怕空)
    • 实际上,你重启后,tomcat会给你自动创建!

docBase 指向的目录 必须提前手动创建好

  • 如果 /opt/admin 不存在,Tomcat 启动会报错,甚至直接失败!
    • 且里面有 index.html 等文件

==访问:==

  • http://diy.kpyun.com/admin → 显示 /opt/admin/index.html

  1. appBase —— “主应用基地”
  • 位置:写在 <Host> 标签里,比如你的例子中是 /code/diy/
  • 作用:这个虚拟主机(比如 diy.kpyun.com默认放 Web 应用的地方
  • 类比:就像你家的“主卧室”,默认所有衣服都放这里
    • 如果你不特别说明,Tomcat 会在这个目录下找应用
  • 注意:如果用户访问 http://diy.kpyun.com/(根路径),Tomcat 会去找 /code/diy/ROOT/ 这个文件夹(因为 ROOT 是默认应用名)

✅ 所以 appBase 是“主机级别的默认应用存放目录”


  1. path —— “网址路径”
  • 位置:写在 <Context> 标签里,比如 path="/admin"
  • 作用:告诉 Tomcat:“当用户访问http://diy.kpyun.com/admin 就用我这个配置!”
  • 注意path 决定了 URL 的哪一段会触发这个 Context

path = URL 中的路径部分,用来“匹配请求”


  1. docBase —— “实际文件在哪”
  • 位置:也在 <Context> 里,比如 docBase="/opt/admin"
  • 作用:真正存放网页、JSP、HTML、Java 程序的物理文件夹
  • 类比:虽然门牌是“admin号房间”(path="/admin"
    • 但这个房间其实不在主卧(appBase
    • 而是在地下室/opt/admin
    • docBase 就是指向这个真实位置的地址
  • 关键点docBase 可以在 appBase 里面,==也可以在外面==

docBase = 真实文件系统路径,和 path 配对使用

Terminal window
<!--复制一份Host自定义为diy.kpyun.com 代码目录指向/code/diy-->
<Host name="diy.kpyun.com" appBase="/code/diy"
unpackWARs="true" autoDeploy="true">
<!--修改了域名和代码目录-->
<Context path="/admin" docBase="/opt/admin" reloadable="true" />
<!-- 多了一行Context-->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="diy.kpyun.com" suffix=".log"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
[root@web01 conf]# mkdir /opt/admin
[root@web01 conf]# echo This is Context > /opt/admin/index.html
[root@web01 conf]# systemctl restart tomcat
'开另一个窗口看日志!'
start Starting ProtocolHandler ["http-nio-8080"]
start Server startup in [497] milliseconds
# 成功启动!
[root@web01 conf]# curl diy.kpyun.com:8080/admin
# 第一次试着拉取,没有东西!
[root@web01 conf]# curl diy.kpyun.com:8080
diy...
# 但是这个默认的页面是有东西的呀!
[root@web01 conf]# cat /opt/admin/index.html
This is Context
# 查看了一下index页面下的内容!
[root@web01 conf]# curl diy.kpyun.com:8080/admin
# 又试着拉取了一次!
'还是不行!没有东西!'
[root@web01 ~]# cd /soft/tomcat/logs/
[root@web01 logs]# ll |grep diy.kpyun
-rw-r----- 1 root root 830 Mar 23 19:17 diy.kpyun.com.2026-03-23.log
# 没招了,看日志去了!
[root@web01 logs]# tail diy.kpyun.com.2026-03-23.log
10.0.0.7 - [23/Mar/2026:19:06:29] "GET /admin HTTP/1.1" 302 -
10.0.0.7 - [23/Mar/2026:19:07:29] "GET /admin/ HTTP/1.1" 200 16
10.0.0.7 - [23/Mar/2026:19:17:16] "GET /admin HTTP/1.1" 302 -
'这里就有问题了,为啥是302,临时跳转???'
====================================
[root@web01 conf]# curl -L diy.kpyun.com:8080/admin
验证:用 -L 参数让 curl 自动跟随重定向
This is Context
这就对了!-L 告诉 curl:如果遇到 301/302,自动跳转
[root@web01 conf]# curl diy.kpyun.com:8080/admin/
This is Context
# 加上/后,就没有跳转了!
[root@web01 logs]# tail -1 diy.kpyun.com.2026-03-23.log
10.0.0.7 - [23/Mar/2026:19:26:03] "GET /admin/ HTTP/1.1" 200 16
根本原因在于:
🔸 /admin(无结尾斜杠) /admin/(有结尾斜杠)在 Tomcat 中被视为不同路径
# 且 Tomcat 会对“目录类路径”自动重定向(302)到带斜杠的形式

curl命令#

选项简单说明
-v显示详细请求/响应过程(包括 headers、连接信息等),用于调试
-L自动跟随 HTTP 重定向(如 301/302),常与 -v 配合使用
-I并仅获取响应头(不返回 body)
-iheaders + body
-o将响应保存到文件,文件可以重复名
-k忽略 SSL 证书验证
即使服务器的 SSL 证书无效、过期或不被信任,curl 也会继续执行请求
-s抑制进度条和错误消息的输出
-S(大写)配合 -s(小写) 使用,在静默模式下,如果发生错误,仍然显示错误信息
Terminal window
(1)-v(小写)详细的过程!
[root@web01 logs]# curl -v diy.kpyun.com:8080/admin/
* Trying 10.0.0.7:8080...
* Connected to diy.kpyun.com (10.0.0.7) port 8080 (#0)
> GET /admin/ HTTP/1.1
> Host: diy.kpyun.com:8080
> User-Agent: curl/7.71.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Accept-Ranges: bytes
< ETag: W/"16-1774263391000"
< Last-Modified: Mon, 23 Mar 2026 10:56:31 GMT
< Content-Type: text/html
< Content-Length: 16
< Date: Mon, 23 Mar 2026 11:47:30 GMT
<
This is Context
* Connection #0 to host diy.kpyun.com left intact
(2)自动重定向
[root@web01 logs]# curl diy.kpyun.com:8080/admin
# 结尾没有/,tomcat会302重定向到/admin/(末尾有/)
[root@web01 logs]# curl -L diy.kpyun.com:8080/admin
This is Context
'加上-L后自动重定向,用户无感知!'
(3)仅获取响应头
[root@web01 logs]# curl -I diy.kpyun.com:8080/admin/
HTTP/1.1 200
Accept-Ranges: bytes
ETag: W/"16-1774263391000"
Last-Modified: Mon, 23 Mar 2026 10:56:31 GMT
Content-Type: text/html
Content-Length: 16
Date: Mon, 23 Mar 2026 11:53:05 GMT
(4)正常返回headers + body
[root@web01 logs]# curl -i diy.kpyun.com:8080/admin/
HTTP/1.1 200
Accept-Ranges: bytes
ETag: W/"16-1774263391000"
Last-Modified: Mon, 23 Mar 2026 10:56:31 GMT
Content-Type: text/html
Content-Length: 16
Date: Mon, 23 Mar 2026 11:53:49 GMT
This is Context
'包含body内容!!'
(5)下载
[root@web01 logs]# curl diy.kpyun.com:8080/admin/index.html -o /home/hh.txt
% Total % Received ...
100 16 100 16 ...
[root@web01 logs]# ll /home/hh.txt
-rw-r--r-- 1 root root 16 Mar 23 19:57 /home/hh.txt
[root@web01 logs]# cat /home/hh.txt
This is Context

管理界面#

image-20260324082629950
image-20260324082629950

Terminal window
它们需通过角色 manager-gui admin-gui 授权访问
1.管理页面,都将权限赋予给了角色,而角色的名称是固定的
2.需要添加一个用户,将用户捆绑至对应的角色
3.尽管配置了用户和角色,但默认仅允许 127.0.0.1 访问
因此需修改以下文件以允许外部访问:
/webapps/manager/META-INF/context.xml
/webapps/host-manager/META-INF/context.xml
📌注意:管理页面中的配置是临时的,未写入配置文件中,❌️重启或覆盖可能丢失!
====================================
管理页面的用户仅用于 Web 应用内部的身份验证,它只是一个逻辑账号!
'不需要系统中存在真实用户'
====================================
[root@web01 conf]# tail -4 /soft/tomcat/conf/tomcat-users.xml
'将下面3行内容复制到 倒数第1行 的上面'
<role rolename="manager-gui"/>
<role rolename="admin-gui"/>
<user username="tomcat" password="123456" roles="manager-gui,admin-gui"/>
<!--我们只需要复制上面三行-->
</tomcat-users>
<!--后面这个是它自带的,不要删-->
[root@web01 ~]# id tomcat
id: ‘tomcat’: no such user
# 它是一个逻辑用户只用于web登录!
[root@web01 ROOT]# vim /soft/tomcat/webapps/host-manager/META-INF/context.xml
[root@web01 ROOT]# vim /soft/tomcat/webapps/manager/META-INF/context.xml
默认状态:allow="127.0.0.0/8,::1/128" />
修改后的状态:allow="10.0.0.0/8,::1/128" />
[root@web01 conf]# systemctl restart tomcat
'重启生效'
[root@web01 ~]# cd /soft/tomcat/logs/
# 再开一个窗口,看一下日志,到底有没有报错!
[root@web01 logs]# tail -f catalina.out
Starting ProtocolHandler ["http-nio-8080"]
startup in [455] milliseconds
'成功启动!'

image-20260324085035047
image-20260324085035047

  • 点击管理页面,需要输入 用户名密码

image-20260324085233135
image-20260324085233135

image-20260324090420137
image-20260324090420137

image-20260324090702151
image-20260324090702151

Terminal window
这个目录,我并没有创建过!
[root@web01 ~]# ll -d /hh/test
drwxr-x--- 2 root root 6 Mar 24 09:06 /hh/test
# 自己给我创建了这个主程序库!
Windows 解析一下!
10.0.0.7 test.oldboy.com

image-20260324090943856
image-20260324090943856

Terminal window
'这是主程序库(/hh/test/)因为没有ROOT目录'
[root@web01 ~]# mkdir /hh/test/ROOT/
[root@web01 ~]# echo test > /hh/test/ROOT/index.html
再次测试访问!

image-20260324091158708
image-20260324091158708

Terminal window
[root@web01 ~]# grep -r 'test.oldboy.com' /soft/tomcat/conf/
[root@web01 ~]# grep 'test.oldboy.com' /soft/tomcat/conf/server.xml
'配置文件压根没有这个Host...'
# 并没有写入到配置文件中!

image-20260324091518277
image-20260324091518277

Terminal window
'临时生效!!'
[root@web01 ~]# systemctl stop tomcat
[root@web01 ~]# systemctl start tomcat
# 关闭再启动,就失效了!

image-20260324091916247
image-20260324091916247


image-20260324093835089
image-20260324093835089

image-20260324094125048
image-20260324094125048

Terminal window
拷贝失败...
# 因为现在我们没有这个真实路径!
[root@web01 ~]# ll /opt/test
ls: cannot access '/opt/test': No such file or directory
[root@web01 ~]# mkdir /opt/test
[root@web01 ~]# echo ceshi... > /opt/test/index.html
# 创建并给个首页!

image-20260324094434985
image-20260324094434985

  • 现在就能够访问了 /test/
    • 同样是 ==临时生效==
    • ==10.0.0.7== 本机的IP地址

image-20260324094547052
image-20260324094547052

部署zrlog博客#

Terminal window
(1)下载zrlog博客!
[root@web01 ~]# mkdir /code/zrlog
[root@web01 ~]# wget https://dl.zrlog.com/release/javax-war/zrlog.war -P /code/zrlog/
[root@web01 ~]# ll /code/zrlog/
total 10544
-rw-r--r-- 1 root root 10794045 Jul 1 2025 zrlog.war
[root@web01 ~]# cd /code/zrlog/
[root@web01 zrlog]# mv zrlog.war ROOT.war
[root@web01 zrlog]# ll
total 10544
-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war
# 改为ROOT.war包!
(2)修改配置文件
#第一步 配置server
[root@web01 ~]# cd /soft/tomcat/conf/
[root@web01 conf]# vim server.xml
...
<Host name="zrlog.kpyun.com" appBase="/code/zrlog"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="zrlog.kpyun.com" suffix=".log"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
# 添加主机即可!
[root@web01 conf]# systemctl restart tomcat
# 重启生效
[root@web01 conf]# cd /code/zrlog/
[root@web01 zrlog]# ll
total 10544
drwxr-x--- 9 root root 126 Mar 24 10:03 ROOT
-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war
# 原来只有.war包,现在启动后,自动解压并部署.war包!
[root@web01 zrlog]# rm -rf ROOT
[root@web01 zrlog]# ll
total 10544
-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war
[root@web01 zrlog]# ll
total 10544
drwxr-x--- 9 root root 107 Mar 24 10:31 ROOT
-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war
# 我把ROOT删除后,他自动部署了ROOT!
# autoDeploy在发力ing
====================================
unpackWARs="true"
🛡️'自动解压'-->每次启动都会解压(只要.war 存在)
# 也就是只要restart一次,就会把.war包解压出来--》ROOT
# 后续我们会把.war包删除的!--》防止业务覆盖!
# 防止覆盖原有的ROOT应用!
autoDeploy="true"
🛡️'自动部署'-->持续监控 webapps/ 目录:
1.删除ROOT,如果.war存在,自动解压部署为ROOT
2.删除.war包,自动卸载对应ROOT应用
# Tomcat 认为“这个应用不再需要” → 自动删除 ROOT/ 目录
====================================
unpackWARs="true" autoDeploy="false"
# 通常会开启自动解压(重启生效),关闭自动部署!
# 解压后删除源.war包,防止业务覆盖!
[root@web01 zrlog]# ll
total 10544
drwxr-x--- 9 root root 126 Mar 24 10:31 ROOT
-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war
[root@web01 zrlog]# rm -rf ROOT
[root@web01 zrlog]# ll
total 10544
-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war
[root@web01 zrlog]# ll
total 10544
-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war
'ROOT删除后没有持续监控'
# 因为我们把 autoDeploy="false"关了
[root@web01 zrlog]# systemctl restart tomcat
# 重启后触发自动解压
[root@web01 zrlog]# ll
total 10544
drwxr-x--- 9 root root 126 Mar 24 11:14 ROOT
-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war
[root@web01 zrlog]# rm -rf ROOT.war
# 删除war包,防止业务覆盖!
[root@web01 zrlog]# ll
total 0
drwxr-x--- 9 root root 126 Mar 24 11:14 ROOT
# 因为autoDeploy="false"关闭
# 删除.war包后,不会删除对应的应用ROOT
(3)数据库准备
# 保证db01开启!
'前提,有一个可以远程登录的用户'
⚠️我这里是jiuzhao oldboy123.com
[root@web01 zrlog]# mysql -h 172.16.1.51 -ujiuzhao -poldboy123.com -e "show databases;"
'这里是在web01执行的!'
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| wordpress |
| zh |
+--------------------+
[root@web01 zrlog]# mysql -h 172.16.1.51 -ujiuzhao -poldboy123.com -e "create database zrlog;"
# 远程创建!
# 创建数据库zrlog
[root@web01 zrlog]# mysql -h 172.16.1.51 -ujiuzhao -poldboy123.com -e "show databases;"|grep zrlog
zrlog
# 相应的数据库已被创建出来!
(4)浏览器测试访问
Windows host表解析
10.0.0.7 zrlog.kpyun.com
# 安装部署流程

image-20260324115338310
image-20260324115338310

image-20260324115511591
image-20260324115511591

image-20260324115523150
image-20260324115523150

image-20260324115710516
image-20260324115710516

image-20260324115738473
image-20260324115738473

image-20260324141444213
image-20260324141444213

权限分析#

  1. 本地文件写入(如上传图片)
    1. ——使用的是运行 Tomcat 的系统用户身份

如果你用 root 启动 Tomcat(/soft/tomcat/bin/startup.sh) 那么:

  • Tomcat 进程的 Linux 用户就是 root
  • 所有由 Java 应用(zrlog)执行的文件操作(如上传图片、写日志、生成缓存等)都以 root 身份进行

  1. 数据库操作(如发布文章)
    1. 连接中配置的数据库账号
操作类型权限主体是否受 Tomcat 启动用户影响
上传图片、写日志、生成文件Linux 系统用户✅ 是
发布文章、读写数据库数据库账号(如 jiuzhao❌ 否

资源位置#

image-20260324144248146
image-20260324144248146

如何快速定位一个网站资源的位置???

  1. 找配置文件

  2. 在配置文件中找对应的域名,看对应代码目录!

Terminal window
[root@web01 zrlog]# cd /soft/tomcat/conf/
[root@web01 conf]# vim server.xml
<Host name="zrlog.kpyun.com" appBase="/code/zrlog"
unpackWARs="true" autoDeploy="false">
# appBase=/code/zrlog
'找到网站根目录!'
[root@web01 conf]# cd /code/zrlog/
[root@web01 zrlog]# ll
total 0
drwxr-x--- 10 root root 142 Mar 24 14:11 ROOT
[root@web01 zrlog]# cd ./ROOT/attached/image/20260324/
'这个ROOT就是根!'
# /attach..这个就是浏览器显示的地址!
[root@web01 20260324]# ll
total 344
-rw-r----- 1 root root 112362 Mar 24 14:11 20260324141113_443.jpg

优化#

Nginx跳转+https#

Terminal window
'单台实现80访问tomcat'
[root@web01 conf.d]# cat tom.conf
server{
listen 80;
server_name zrlog.kpyun.com;
return 302 https://$server_name$request_uri;
}
server{
listen 443 ssl;
server_name zrlog.kpyun.com;
ssl_certificate ./ssl_key/server.crt;
ssl_certificate_key ./ssl_key/server.key;
location / {
proxy_pass http://127.0.0.1:8080;
# 请求本地的8080,同时带上请求头,版本号
proxy_set_header Host $http_host;
proxy_http_version 1.1;
}
}
[root@web01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@web01 conf.d]# systemctl restart nginx

image-20260324150937263
image-20260324150937263

集群#

Terminal window
'优先配置ssh免密登录!'
(1)web02部署JDK
[root@web02 ~]# scp 10.0.0.7:/server/tmp/jdk* /server/tmp/
jdk-8u181-linux-x64.rpm 100% 162MB
[root@web02 ~]# cd /server/tmp/
[root@web02 tmp]# rpm -ivh jdk-8u181-linux-x64.rpm
[root@web02 tmp]# java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
(2)web部署Tomcat
[root@web02 tmp]# scp -r 10.0.0.7:/soft /
# 把整个soft目录拷贝过来了
(3)代码同步拷贝
[root@web02 tmp]# scp -r 10.0.0.7:/code/zrlog /code/
(4)配置systemctl启动方式
[root@web02 tmp]# scp 10.0.0.7:/usr/lib/systemd/system/tomcat.service /usr/lib/systemd/system/
tomcat.service 100% 235 188.7KB/s
[root@web02 tmp]# systemctl daemon-reload
(5)修改配置文件
[root@web02 tmp]# vim /soft/tomcat/conf/server.xml
<!--复制一份Host自定义为diy.kpyun.com 代码目录指向/code/diy-->
# 把原来的diy.kpyun.com的配置文件删除了
(6)启动tomcat
[root@web02 tmp]# systemctl start tomcat
[root@web02 tmp]# netstat -tnulp | grep 8080
tcp6 :::8080 LISTEN 1757/java
(7)解析测试
# windows hosts解析到10.0.0.8测试zrlog
10.0.0.8 zrlog.kpyun.com
浏览器测试访问:zrlog.kpyun.com:8080

image-20260324155511461
image-20260324155511461

Terminal window
(8)负载均衡配置
'lb01'
# 当然我们也可以配置高可用!
# 后面再配置吧
[root@lb01 ~]# cd /etc/nginx/conf.d/
[root@lb01 conf.d]# vim zrlog.conf
server {
listen 80;
server_name zrlog.kpyun.com;
# return 302 https://$server_name$request_uri;
rewrite ^(.*)$ https://$server_name$request_uri redirect;
# 临时跳转,每次请求都要先请求源站
}
upstream tom {
server 172.16.1.7:8080;
server 172.16.1.8:8080;
}
server {
listen 443 ssl;
server_name zrlog.kpyun.com;
ssl_certificate ssl_key/server.crt;
ssl_certificate_key ssl_key/server.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
include lb_env;
# 负载的其他配置!
location / {
proxy_pass http://tom;
}
}
[root@lb01 conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@lb01 conf.d]# systemctl restart nginx
(9)Windows解析
10.0.0.5 zrlog.kpyun.com

image-20260324161713720
image-20260324161713720

静态资源挂载#

Terminal window
(1)找到图片的位置
https://zrlog.kpyun.com/attached/image/20260324/
[root@web01 conf]# cd /code/zrlog/
[root@web01 zrlog]# ll
total 0
drwxr-x--- 10 root root 142 Mar 24 14:11 ROOT
[root@web01 ~]# cd /code/zrlog/
[root@web01 zrlog]# ll ./ROOT/attached/image/
'这个ROOT就是根!'
drwxr-x--- 2 root root 76 Mar 24 14:11 20260324
# 我们挂载image就够了!
(2)配置NFS
[root@nfs ~]# vim /etc/exports
/data/zrlog 172.16.1.0/24(rw,sync,all_squash,anonuid=666,anongid=666)
[root@nfs ~]# mkdir /data/zrlog
[root@nfs ~]# chown www.www /data/zrlog
[root@nfs ~]# systemctl restart nfs
[root@nfs ~]# showmount -e 172.16.1.31 | grep zrlog
/data/zrlog 172.16.1.0/24
# 成功嗅探!
(3)将上传的图片拷贝到NFS
# 那张小狗
[root@web02 zrlog]# scp -r /code/zrlog/ROOT/attached/image 10.0.0.31:/data/zrlog/
[root@nfs ~]# chown -R www.www /data/zrlog/
[root@nfs ~]# ll /data/zrlog/
total 0
drwxr-x--- 3 www www 19 Aug 22 11:53 attached
(4)传输并挂载
[root@nfs ~]# scp -r 172.16.1.7:/code/zrlog/ROOT/attached/image /data/zrlog/
root@172.16.1.7's password: '
20260324141113_443.jpg 100% 110KB
20260324141113_443_thumbnail.jpg 100% 230KB
[root@web01 ~]# mount -t nfs 172.16.1.31:/data/zrlog /code/zrlog/ROOT/attached/
[root@web01 ~]# df -h |grep zrlog
172.16.1.31:/data/zrlog 49G 4.0G 45G 9% /code/zrlog/ROOT/attached
'web02挂载!'
[root@web02 tmp]# mount -t nfs 172.16.1.31:/data/zrlog /code/zrlog/ROOT/attached/
[root@web02 tmp]# df -h |grep zrlog
172.16.1.31:/data/zrlog 49G 4.0G 45G 9% /code/zrlog/ROOT/attached
====================================
❗注意Nginx默认上传的限制
vim /etc/nginx/nginx.conf
# 写在http区块即可
[root@lb01 conf.d]# grep body_size /etc/nginx/nginx.conf
client_max_body_size 20M;

image-20260324164649301
image-20260324164649301

Terminal window
我发现图片没了❓
'先看web服务器!'
[root@web01 ~]# cd /code/zrlog/ROOT/attached/
[root@web01 attached]# ll
total 0
drwxr-x--- 3 root root 22 Mar 24 16:31 image
# 这个东西是在nfs服务器中的!
[root@web01 attached]# cd image/
-bash: cd: image/: Permission denied
====================================
'再看nfs服务器!'
[root@nfs ~]# ll /data | grep zrlog
drwxr-xr-x 3 www www 19 Mar 24 16:31 zrlog
# 这个还是www
[root@nfs ~]# ll /data/zrlog/
drwxr-x--- 3 root root 22 Mar 24 16:31 image
# 到这里变为root,
anonuid=666,anongid=666
'nfs的压缩用户是www'
[root@nfs ~]# chown -R www.www /data/zrlog/
[root@nfs ~]# ll /data/zrlog/
total 0
drwxr-x--- 3 www www 22 Mar 24 16:31 image
====================================
'修改完权限再次回到web服务器!!'
[root@web01 attached]# ll
total 0
drwxr-x--- 3 www www 22 Mar 24 16:31 image
[root@web01 attached]# cd image/
[root@web01 image]# ll
total 0
drwxr-x--- 2 www www 76 Mar 24 16:31 20260324
💡这次就能够顺利将进入了!
  • ==核心原因分析==

你遇到的现象是:

  • Web 服务器操作者:你在 Web 服务器上使用的是 root 用户
  • 实际生效身份:当你访问 NFS 挂载点时,你的身份被强制映射成了 UID 666 (www)

根本原因:这是因为你的 NFS 导出配置中使用了 all_squash

无论客户端是谁(哪怕是 root),所有访问该共享目录的用户(包括 root)都会被强制映射为匿名用户的 UID/GID

  • [root@nfs ~]# id www uid=666(www) gid=666(www) groups=666(www)
  • 也就是 NFSwww用户
Terminal window
❌️修改前:
drwxr-x--- 3 root root 22 Mar 24 16:31 image
# nfs压缩用户是www,而Others 的权限是 --- (0),所以 Permission denied
✅️修改后:
drwxr-x--- 3 www www 22 Mar 24 16:31 image
# Owner 的权限是 rwx (7),所以允许进入,并且随意更改!

image-20260324172855810
image-20260324172855810

  • ==成功上传并写入!==

image-20260324172913618
image-20260324172913618

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Tomcat开篇
https://www.kpyun.fun/posts/web/tomcat/tomcat01/
作者
久棹
发布于
2026-01-03
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录