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 服务器的区别
| Nginx | Tomcat | |
|---|---|---|
| 类型 | 高性能 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等) |
| 谁负责运行? | JVM | Tomcat(或其他 Web 容器) |
部署Tomcat
| Tomcat 版本 | 最低 JDK 要求 | 推荐 JDK 版本 |
|---|---|---|
| Tomcat 11 | JDK 17 | JDK 17+ |
| Tomcat 10.x | JDK 8(但部分功能需 JDK 11) | JDK 11+ |
| Tomcat 9.x | JDK 8 | JDK 8 或 JDK 11 |
- Tomcat官网 https://tomcat.apache.org/
- 我们这里是
Tomcat 9.x版本
| 场景 | 推荐 JDK |
|---|---|
| 老项目、传统系统、追求稳定 | ✅ JDK 8(最经典,兼容性最好) |
| 想用新点的 JDK(如 LTS 版本),且无特殊依赖 | ✅ JDK 11(也是 LTS,性能更好) |

'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 jdkjdk1.8-1.8.0_181-fcs.x86_64# 检查[root@web01 tmp]# java -versionjava 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 0drwxr-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 0drwxr-xr-x 9 root root 220 Mar 23 10:32 apache-tomcat-9.0.113lrwxrwxrwx 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]# lsstartup.sh shutdown.sh'主要是这俩进行控制启停!'# 里面还有一些是以.bat结尾的文件-->Win启停![root@web01 bin]# startup.sh-bash: startup.sh: command not found'必须要以./开头!当前路径下!'[root@web01 bin]# ./startup.sh# 相对路径启动TomcatUsing CATALINA_BASE: /soft/tomcat...Tomcat started.[root@web01 ~]# /soft/tomcat/bin/startup.shTomcat started.# 绝对路径启动Tomcat[root@web01 ~]# ss -lntup |grep 8080# 默认运行端口8080tcp LISTEN .. *:8080 (("java",pid=1679,fd=58))
浏览器测试访问!
systemd启动
# 这里我们把配置文件放在了'/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.shExecStop=/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/javaMar 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 8080tcp 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主配置文件
[root@web01 ~]# cd /soft/tomcat/conf/[root@web01 conf]# lsCatalina ...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 里 |
<?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 "%r" %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 "%r" %s %b" /> </Host>
</Engine> </Service></Server>快速部署
Host
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 "%r" %s %b" /> </Host> <!--日志修改了位置和后缀-->
</Engine> </Service></Server>===================================='重新开一个窗口'[root@web01 ~]# cd /soft/tomcat/logs/[root@web01 logs]# ls...localhost_access_log.2026-03-23.txtcatalina.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/hosts10.0.0.7 diy.kpyun.com'本地hosts解析'[root@web01 conf]# curl diy.kpyun.com:8080HTTP 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:8080diy...'成功拉取到!'关键词通俗解释
💡举个完整例子
- 你有域名:
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
appBase—— “主应用基地”
- 位置:写在
<Host>标签里,比如你的例子中是/code/diy/ - 作用:这个虚拟主机(比如
diy.kpyun.com) 默认放 Web 应用的地方 - 类比:就像你家的“主卧室”,默认所有衣服都放这里
- 如果你不特别说明,Tomcat 会在这个目录下找应用
- 注意:如果用户访问
http://diy.kpyun.com/(根路径),Tomcat 会去找/code/diy/ROOT/这个文件夹(因为 ROOT 是默认应用名)
✅ 所以
appBase是“主机级别的默认应用存放目录”
path—— “网址路径”
- 位置:写在
<Context>标签里,比如path="/admin" - 作用:告诉 Tomcat:“当用户访问
http://diy.kpyun.com/admin就用我这个配置!” - 注意:
path决定了 URL 的哪一段会触发这个 Context
✅
path= URL 中的路径部分,用来“匹配请求”
docBase—— “实际文件在哪”
- 位置:也在
<Context>里,比如docBase="/opt/admin" - 作用:真正存放网页、JSP、HTML、Java 程序的物理文件夹
- 类比:虽然门牌是“admin号房间”(
path="/admin")- 但这个房间其实不在主卧(
appBase) - 而是在地下室(
/opt/admin) docBase就是指向这个真实位置的地址
- 但这个房间其实不在主卧(
- 关键点:
docBase可以在appBase里面,==也可以在外面==
✅
docBase= 真实文件系统路径,和path配对使用
<!--复制一份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 "%r" %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:8080diy...# 但是这个默认的页面是有东西的呀![root@web01 conf]# cat /opt/admin/index.htmlThis 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.log10.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 1610.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.log10.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) |
-i | headers + body |
-o | 将响应保存到文件,文件可以重复名 |
-k | 忽略 SSL 证书验证 即使服务器的 SSL 证书无效、过期或不被信任,curl 也会继续执行请求 |
-s | 抑制进度条和错误消息的输出 |
-S(大写) | 配合 -s(小写) 使用,在静默模式下,如果发生错误,仍然显示错误信息 |
(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/adminThis is Context'加上-L后自动重定向,用户无感知!'
(3)仅获取响应头[root@web01 logs]# curl -I diy.kpyun.com:8080/admin/HTTP/1.1 200Accept-Ranges: bytesETag: W/"16-1774263391000"Last-Modified: Mon, 23 Mar 2026 10:56:31 GMTContent-Type: text/htmlContent-Length: 16Date: Mon, 23 Mar 2026 11:53:05 GMT
(4)正常返回headers + body[root@web01 logs]# curl -i diy.kpyun.com:8080/admin/HTTP/1.1 200Accept-Ranges: bytesETag: W/"16-1774263391000"Last-Modified: Mon, 23 Mar 2026 10:56:31 GMTContent-Type: text/htmlContent-Length: 16Date: 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.txtThis is Context管理界面

它们需通过角色 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 tomcatid: ‘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.outStarting ProtocolHandler ["http-nio-8080"]startup in [455] milliseconds'成功启动!'
- 点击管理页面,需要输入
用户名和密码



这个目录,我并没有创建过![root@web01 ~]# ll -d /hh/testdrwxr-x--- 2 root root 6 Mar 24 09:06 /hh/test# 自己给我创建了这个主程序库!
Windows 解析一下!10.0.0.7 test.oldboy.com
'这是主程序库(/hh/test/)因为没有ROOT目录'[root@web01 ~]# mkdir /hh/test/ROOT/[root@web01 ~]# echo test > /hh/test/ROOT/index.html
再次测试访问!
[root@web01 ~]# grep -r 'test.oldboy.com' /soft/tomcat/conf/[root@web01 ~]# grep 'test.oldboy.com' /soft/tomcat/conf/server.xml'配置文件压根没有这个Host...'# 并没有写入到配置文件中!
'临时生效!!'[root@web01 ~]# systemctl stop tomcat[root@web01 ~]# systemctl start tomcat# 关闭再启动,就失效了!


拷贝失败...# 因为现在我们没有这个真实路径![root@web01 ~]# ll /opt/testls: cannot access '/opt/test': No such file or directory[root@web01 ~]# mkdir /opt/test[root@web01 ~]# echo ceshi... > /opt/test/index.html# 创建并给个首页!
- 现在就能够访问了
/test/- 同样是 ==临时生效==
- ==10.0.0.7== 本机的IP地址

部署zrlog博客
(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]# lltotal 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 "%r" %s %b" /> </Host># 添加主机即可![root@web01 conf]# systemctl restart tomcat# 重启生效[root@web01 conf]# cd /code/zrlog/[root@web01 zrlog]# lltotal 10544drwxr-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]# lltotal 10544-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war[root@web01 zrlog]# lltotal 10544drwxr-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存在,自动解压部署为ROOT2.删除.war包,自动卸载对应ROOT应用# Tomcat 认为“这个应用不再需要” → 自动删除 ROOT/ 目录====================================unpackWARs="true" autoDeploy="false"# 通常会开启自动解压(重启生效),关闭自动部署!# 解压后删除源.war包,防止业务覆盖![root@web01 zrlog]# lltotal 10544drwxr-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]# lltotal 10544-rw-r--r-- 1 root root 10794045 Jul 1 2025 ROOT.war[root@web01 zrlog]# lltotal 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]# lltotal 10544drwxr-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]# lltotal 0drwxr-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 zrlogzrlog# 相应的数据库已被创建出来!
(4)浏览器测试访问Windows host表解析10.0.0.7 zrlog.kpyun.com# 安装部署流程





权限分析
- 本地文件写入(如上传图片)
- ——使用的是运行 Tomcat 的系统用户身份
如果你用 root 启动 Tomcat(/soft/tomcat/bin/startup.sh) 那么:
- Tomcat 进程的 Linux 用户就是
root - 所有由 Java 应用(zrlog)执行的文件操作(如上传图片、写日志、生成缓存等)都以
root身份进行
- 数据库操作(如发布文章)
- 连接中配置的数据库账号
| 操作类型 | 权限主体 | 是否受 Tomcat 启动用户影响 |
|---|---|---|
| 上传图片、写日志、生成文件 | Linux 系统用户 | ✅ 是 |
| 发布文章、读写数据库 | 数据库账号(如 jiuzhao) | ❌ 否 |
资源位置

如何快速定位一个网站资源的位置???
-
找配置文件
-
在配置文件中找对应的域名,看对应代码目录!
[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]# lltotal 0drwxr-x--- 10 root root 142 Mar 24 14:11 ROOT[root@web01 zrlog]# cd ./ROOT/attached/image/20260324/'这个ROOT就是根!'# /attach..这个就是浏览器显示的地址![root@web01 20260324]# lltotal 344-rw-r----- 1 root root 112362 Mar 24 14:11 20260324141113_443.jpg优化
Nginx跳转+https
'单台实现80访问tomcat'
[root@web01 conf.d]# cat tom.confserver{ 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 -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful[root@web01 conf.d]# systemctl restart nginx
集群
'优先配置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 -versionjava 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 8080tcp6 :::8080 LISTEN 1757/java
(7)解析测试# windows hosts解析到10.0.0.8测试zrlog10.0.0.8 zrlog.kpyun.com浏览器测试访问:zrlog.kpyun.com:8080
(8)负载均衡配置'lb01'# 当然我们也可以配置高可用!# 后面再配置吧[root@lb01 ~]# cd /etc/nginx/conf.d/[root@lb01 conf.d]# vim zrlog.confserver { 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 -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: 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
静态资源挂载
(1)找到图片的位置https://zrlog.kpyun.com/attached/image/20260324/[root@web01 conf]# cd /code/zrlog/[root@web01 zrlog]# lltotal 0drwxr-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 0drwxr-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% 110KB20260324141113_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 zrlog172.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 zrlog172.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;
我发现图片没了❓'先看web服务器!'[root@web01 ~]# cd /code/zrlog/ROOT/attached/[root@web01 attached]# lltotal 0drwxr-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 zrlogdrwxr-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 0drwxr-x--- 3 www www 22 Mar 24 16:31 image===================================='修改完权限再次回到web服务器!!'[root@web01 attached]# lltotal 0drwxr-x--- 3 www www 22 Mar 24 16:31 image[root@web01 attached]# cd image/[root@web01 image]# lltotal 0drwxr-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)
- 也就是
NFS的 www用户
❌️修改前: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),所以允许进入,并且随意更改!
- ==成功上传并写入!==

文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
Tomcat动静分离
Web服务Tomcat动静分离与多端适配实战,通过Redis共享Session、Nginx正则分发及User-Agent路由
2
前后端分离
Web服务前后端分离架构实战,涵盖Spring Boot后端、Nginx前端部署及四层七层负载均衡集群
3
函数与数组
Shell脚本Shell函数定义与数组操作,涵盖局部/全局变量、递归函数及数组遍历
4
循环与case多分支
Shell脚本Shell循环结构与case多分支语句,涵盖for/while/until循环及实战脚本
5
数值运算与if条件判断
Shell脚本Shell数值运算方法与if条件判断结构,涵盖整数/字符串比较及文件测试
随机文章随机推荐



