108 篇把 JDK、MySQL、Nginx 三样装进了服务器,环境齐了。这一篇(PPT 第 63~70 页)是第 19 章的收官:把 Tlias 这个项目真正搬到服务器上跑起来——前端那段静态页面交给 nginx,后端那个 jar 在服务器上跑起来,再让 nginx 把两者合成"一个入口"。
WARNING
这一篇没有在本机实测——跑通它需要一台真实的 Linux 服务器(还要先按 108 篇把 JDK / MySQL / Nginx 装好、把 tlias 库导进去),本轮没有这样的环境。好在里面的关键一步是"见过"的:nginx 的静态托管 + /api 反向代理这一整套,第 7 章在 Windows 上做过并且实测过(那份配置监听 90 端口、把 /api/depts 转给 8080 的 Tomcat)——Linux 上这一套和它是一个道理,只是换成 nginx 装在服务器上、监听 80、后端也换成服务器上的 jar。下面按 PPT 第 63~70 页写。
| PPT 页 | 内容 | 本篇对应小节 |
|---|---|---|
| 63 | 章节目录页(Linux 概述 / 常用命令 / 软件安装 / 项目部署) | 开篇——第一章最后一张卡片 |
| 64 | 小节目录页——"项目部署 04"(前端项目部署 / 后端项目部署) | 部署分两件事 |
| 65 | 前端项目部署(传静态资源 + 改 conf/nginx.conf + sbin/nginx / -s reload) | 前端项目部署 |
| 66 | 问答页——nginx 启动 / 停止 / 重新加载 | nginx 的三条命令 |
| 67 | 同一张目录页(讲完前端回到这里) | 前端项目部署末尾 |
| 68 | 后端项目部署(package 打包 → 传 jar → java -jar → nohup 后台;特殊符号 |、>、>>) | 后端项目部署 |
| 69 | 问答页——后台运行 / 查看进程 / 杀死进程 | 后端的查看与重启 |
| 70 | 空白页——第 19 章收尾 | 本章到此结束 |
这一篇在第一章里的位置(PPT 第 63~64 页)
第 63 页是第一章的目录页:Linux 概述 / Linux 常用命令 / Linux 软件安装 / 项目部署——前三张卡片在 106、107、108 篇已经点亮,本篇点亮最后一张。第 64 页把"项目部署"拆成两件事:
项目部署 → 前端项目部署 / 后端项目部署
这两件事对应的就是我们手里那两个工程(57 篇起就一直是这么分的):
| 部署哪一半 | 工程里的东西 | 在服务器上谁来管 |
|---|---|---|
| 前端 | 105 篇打包出来的静态资源(index.html + assets/ + favicon.ico) | nginx:一份当静态 Web 服务器发页面,一份当反向代理把 /api 转给后端 |
| 后端 | 打出来的 jar 包(tlias-web-management.jar) | 服务器上的 JDK(java -jar 跑起来),连服务器上的 MySQL |
一句话概括这一篇要干的事:前端静态资源放进 nginx 的 html 目录、nginx 配一段反向代理;后端 jar 传到服务器上用 nohup 后台跑起来——两边各就各位之后,用户只访问服务器的那一个地址(80 端口),页面和数据就都有了。
前端项目部署(PPT 第 65 页)
第 65 页把前端部署写成三步:
- 将
资料\06.项目部署\前端\页面资源文件夹下的打包好的静态资源,上传到 nginx 的 html 目录中。- 配置 nginx 的配置文件,在
conf/nginx.conf中配置反向代理服务器及路径重写规则。- 在 nginx 的安装目录中,执行
sbin目录下的 nginx 命令启动 nginx 服务:sbin/nginx或sbin/nginx -s reload。
① 静态资源传到哪(PPT 第 65 页第 1 步)
课程资料 资料/06. 项目部署/前端/页面资源/ 里就是一份打包好的前端产物:index.html、assets/(index.xxx.js、index.xxx.css 这些)、favicon.ico——和 105 篇里 npm run build 出来的 dist 是同一种东西(那一份是老师提前打好的)。
落点是nginx 的 html 目录——具体路径跟着 108 篇的安装位置走:nginx 是用 ./configure --prefix=/usr/local/nginx 装的,所以 nginx 的"家"就是 /usr/local/nginx,它的 html 目录就是:
/usr/local/nginx/html/ ← 前端静态资源放这儿(index.html 直接在这一层)
/usr/local/nginx/conf/nginx.conf ← 下面要改的配置文件
/usr/local/nginx/logs/ ← 访问日志、错误日志
/usr/local/nginx/sbin/nginx ← 启动用的可执行文件两个和 105 篇一模一样的注意点,这里再强调一次:
- 传进去的是页面资源里的文件(
index.html、assets/、favicon.ico),不是把"页面资源"这个文件夹整个放进 html——否则访问地址就得带一层目录名,和 PPT 上"访问服务器 IP 就能看到页面"对不上; - 原来的
html/index.html是 nginx 的默认欢迎页(108 篇里验证安装看到的那张「Welcome to nginx!」),传上去之后它就是被覆盖/替换的那一个——所以传完再访问,看到的就是 Tlias 的页面了。
② 改 conf/nginx.conf(PPT 第 65 页第 2 步,逐行讲)
第 65 页把要配的那段贴了出来(它就是 conf/nginx.conf 里 http { … } 里的一个 server 块):
server {
listen 80;
server_name localhost;
client_max_body_size 10m;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location ^~ /api/ {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://localhost:8080;
}
}逐行拆开(和第 7 章那套对照着看,会发现只有"端口"和"部署位置"变了):
| 配置 | 它在干什么 |
|---|---|
server { … } | 一个服务的配置块:里面写的规则,管的是"发到本机某个端口的请求" |
listen 80; | 监听 80 端口。80 是浏览器默认的 HTTP 端口(地址里不写端口时走的就是它),所以这里面必须放"给用户访问的那一个服务"——用户敲 http://192.168.100.128 就等于敲 80 |
server_name localhost; | 匹配域名。这里写 localhost 表示"认这个名字"的请求归它管;实际用 IP 访问也能进——因为这台机器这个端口上只有这一个 server 块,它就是默认服务 |
client_max_body_size 10m; | 允许的请求体最大 10MB(上传文件、提交大表单时不被 nginx 直接拦掉,超了会返回 413) |
location / { … } | 其它所有请求(不在 /api/ 里的)都走这条:去 html 目录里找文件返回——也就是第 ① 步上传的前端页面 |
root html; | 静态文件的根目录,html 是相对路径,相对的是 nginx 的安装目录(--prefix 定的 /usr/local/nginx)——所以实际找的是 /usr/local/nginx/html |
index index.html index.htm; | 访问"目录"时默认返回哪个文件(所以访问 / 就是 html/index.html) |
try_files $uri $uri/ /index.html; | 前端路由兜底:先按请求的路径找文件,找不到就交回 index.html 让页面脚本去处理。单页应用(95 篇那套 Vue 工程)切菜单改的是 URL 而不是真文件,刷新页面就靠这一行不至于 404 |
location ^~ /api/ { … } | 只处理 /api/ 开头的请求(^~ 是前缀匹配、命中后不再试正则)。页面上所有接口请求都带 /api 前缀(99 篇在 request.js 里配的 baseURL: '/api'),所以能被这条规则一眼挑出来 |
rewrite ^/api/(.*)$ /$1 break; | 路径重写:把 /api 这段前缀摘掉——/api/depts → /depts。因为后端接口自己的路径里没有 /api(58 篇是 @GetMapping("/depts")) |
proxy_pass http://localhost:8080; | 代理转发:把(重写后的)请求转给 8080——也就是下面要部署的那个后端 jar。这里写 localhost 不是"本机开发环境"的意思,而是"nginx 所在的这台服务器"——jar 也跑在同一台机器上,所以转发地址还是 localhost:8080,和 第 7 章那份配置一字不差 |
把这一串按一次真实的点击串起来就是:
浏览器敲 http://192.168.100.128 → 落到 80 的 nginx → 匹配 location /,从 /usr/local/nginx/html 取出 index.html(页面回来了)→ 页面脚本发 /api/depts 给同一个 80 → 匹配 location ^~ /api/ → rewrite 成 /depts → proxy_pass 转给 localhost:8080 → 后端 jar 处理 → JSON 原路返回 → 页面渲染出表格。
TIP
和 第 7 章 Windows 上那套对比着看——配置本身一字未改,变的只是"东西放在哪台机器上":
| 对比项 | 第 7 章(Windows 联调) | 本篇(Linux 服务器) |
|---|---|---|
| nginx 在哪、听哪个端口 | Windows 上那份绿色版 nginx,listen 90 | 服务器上装的 nginx,listen 80 |
| 后端在哪 | 开发机上的 IDEA 跑 SpringBoot(8080) | 服务器上的 java -jar(8080) |
| 配置本身 | location / + location ^~ /api/ 那几行 | 一模一样(rewrite、proxy_pass 一字未改) |
为什么能一字不改?因为 proxy_pass http://localhost:8080 里的 localhost 永远指"nginx 自己所在的那台机器"——两套环境里,后端都恰好跑在同一台机器上。"静态托管 + 反向代理"这两件事的道理是同一个。 |
课程资料里给了一份完整的 conf/nginx.conf(资料/06. 项目部署/前端/配置文件/nginx.conf),就是在默认配置的基础上改出来的——worker_processes、events、http 那几层是原样保留的,改的是 http 里的 server 块:
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
client_max_body_size 10m;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location ^~ /api/ {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://localhost:8080;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}(要比对的话:默认的 nginx.conf 里 server 块只有 location / 那几行,client_max_body_size、try_files、整段 location ^~ /api/ 都是这套部署多加进去的;error_page / 50x.html 那两行是 nginx 自带的错误页配置,原样留着。)
③ 启动 / 重载 nginx(PPT 第 65 页第 3 步)
在 nginx 的安装目录里执行:
cd /usr/local/nginx
sbin/nginx # 启动(第一次起服务时用)
sbin/nginx -s reload # 重载(nginx 已经在跑、改了配置时用)两条命令按场景二选一:第一次部署是启动;以后改了 nginx.conf 或换了 html 里的文件,用重载让 nginx 重新读配置——改完配置不重载等于没改(这一点在 105 篇的 Windows 版上就强调过,Linux 上完全一样)。
第 67 页是同一张目录页又出现("项目部署 04"回到前端/后端两个入口)——前端这一半讲完了,接下来轮到后端。
nginx 的启动、停止、重新加载(PPT 第 66 页)
第 66 页把三条命令单拎出来问了一遍(这是最常被问到的一页):
| 操作 | 命令 | 什么时候用 |
|---|---|---|
| 启动 | sbin/nginx | 第一次把服务跑起来(装完 nginx 之后;或停掉之后重新起) |
| 停止 | sbin/nginx -s quit | 不想让它继续跑、要腾出 80 端口的时候(quit 是优雅停止:把手上正在处理的请求处理完再退出) |
| 重新加载 | sbin/nginx -s reload | 改了 conf/nginx.conf 之后必须执行;换了 html 里的页面文件后顺手 reload 一下最稳 |
三个使用细节:
- 命令要在 nginx 的安装目录里执行(
/usr/local/nginx)——sbin/nginx是"当前目录下的相对路径",换个目录就找不到它了; - 想确认它到底在不在跑,用 107 篇的
ps -ef | grep nginx看进程,或者直接访问 80 端口; - 顺带和 105 篇的 Windows 版对上:那边是
nginx.exe/nginx.exe -s reload/nginx.exe -s stop——参数写法一样,只是可执行文件从nginx.exe换成了sbin/nginx(Windows 用stop立即停,Linux 这里课程给的是quit优雅停)。
后端项目部署(PPT 第 68 页)
第 68 页把后端部署写成一条链路,顺便把两个 Linux 特殊符号也讲了:
- 执行 maven 的父工程中的 package 生命周期,对项目进行打包【打包之前,先连接上服务器数据库,先测试通过】。
- 在 linux 服务器的
/usr/local目录下,创建一个目录 tlias-app,将 jar 包上传到服务器的/usr/local/tlias-app目录中。- 然后在命令行执行命令,运行 jar 包:
java -jar xxxxxx.jar- 上述执行运行 jar 包之后,会占用前台窗口,窗口关闭服务也就停了。可以使用 nohup 指令,后台运行服务:
nohup java -jar xxxxxx.jar &> tlias.log &- 查看进程:
ps -ef | grep xxxx
① 打包(注意"先连服务器数据库测通")
在后端工程的 maven 父工程上执行 package(IDEA 右侧 Maven 面板双击 package,或命令行 mvn package),产出可执行的 jar 包(课程资料里那份叫 tlias-web-management.jar,在 资料/06. 项目部署/ 下)。
PPT 括号里的那句提醒是这一节最容易被跳过的地方:"打包之前,先连接上服务器数据库,先测试通过"。意思是:
- 把工程配置文件里的数据源改成服务器上那个 MySQL(
spring.datasource.url指向192.168.100.128:3306、用户名密码用 108 篇改过的root/1234),并把课程给的tlias.sql在服务器 MySQL 上执行、建好库表; - 先在本地把它跑通(56 篇的配置写法、57 篇的工程结构都还是原样,只是连的库换了);
- 确认能正常查数据了,再执行
package。
为什么非要按这个顺序?因为 jar 里打进去的就是打包那一刻的配置——先打包再改数据库地址,等于抱着一份连不上库的 jar 上服务器(启动就报连接失败)。先测通、再打包,jar 到了服务器上才"开箱即跑"。
② 上传 jar 到 /usr/local/tlias-app
mkdir /usr/local/tlias-app在服务器的 /usr/local 下建一个 tlias-app 目录,把 jar 传进去(FinalShell 上传)。为什么单独建目录:服务器的 /usr/local 是"额外安装的应用程序放的位置"(106 篇的目录结构),把项目的 jar 和自己的日志归到一个目录里,比丢在家目录下清楚——好处在重启服务时能看见:目录里除了 jar 还会躺着 nohup 生成的日志。
③ 前台跑一次:java -jar
cd /usr/local/tlias-app
java -jar tlias-web-management.jarJRE/JDK 是 108 篇装好的,所以 java 命令能直接敲。这条命令会把 SpringBoot 应用跑在当前窗口的前台:日志一行行刷在屏幕上、不能关窗口——PPT 说得很直白:"会占用前台窗口,窗口关闭服务也就停了"。第一次部署先用它跑一遍,确认能起来(看到 Tomcat started on port 8080 / Started ...Application),按 Ctrl+C 停掉,再换成下面的后台方式。
④ 后台运行:nohup java -jar xxxxxx.jar &> tlias.log &
nohup java -jar tlias-web-management.jar &> tlias.log &一行命令里三个符号,拆开看:
| 片段 | 作用 |
|---|---|
nohup | "no hang up":让命令不受终端挂断的影响——关掉 FinalShell 窗口、断开 SSH 连接,进程照跑(前台直接跑的话,窗口一关进程就跟着没了) |
&> tlias.log | 把输出(标准输出 + 标准错误)都写进 tlias.log 这个文件里。前台跑时日志刷在屏幕上,后台跑看不见屏幕,就靠这个文件留痕——它相当于项目的运行日志(107 篇的 tail -f tlias.log 就是为它准备的) |
末尾的 & | 放到后台执行:命令立刻返回,窗口还能继续敲别的命令 |
所以这一行的读法就是:"忽略挂断、日志进文件、后台跑"。服务起来后,浏览器/接口工具访问 http://192.168.100.128:8080/… 就能验证(8080 通常不用对外放行——nginx 在服务器内部访问它,这也是反向代理"安全"的体现)。
⑤ 查看进程:ps -ef | grep xxx
ps -ef | grep tlias
ps -ef | grep javaps -ef 列出系统里所有进程,| grep 把关心的那几行筛出来(下面要讲的管道符)——能看见 java -jar tlias-web-management.jar 这一行,就说明服务在跑。
Linux 里的两个特殊符号(PPT 第 68 页)
PPT 在这页末尾专门讲了这两个符号,因为这一节里到处在用:
| 符号 | 名字 | 作用 | 例子 |
|---|---|---|---|
| | 管道符 | 把前面命令的输出,作为后面命令的输入 | ps -ef | grep java——ps -ef 的输出被 grep 筛了一遍 |
> | 重定向符(覆盖) | 把前面的内容输出到后面的文件里,覆盖原内容 | echo 'Hello Linux' > 1.log——1.log 里只剩这一行 |
>> | 重定向符(追加) | 同上,但追加在文件末尾 | echo 'Hello Linux' >> 1.log——1.log 里多一行 |
对号入座一下:nohup … &> tlias.log 里的 &> 就是"标准输出 + 标准错误一起重定向";ps -ef | grep 用的是管道符。
查看与停止后端服务(PPT 第 69 页)
第 69 页把后端运维的三件事问了一遍,答案就是这些命令:
| PPT 的问题 | 答案 |
|---|---|
| 如何让 linux 中的命令在后台运行,不占用前台窗口? | nohup … &>xxx.log & |
| 查看系统进程的命令? | ps -ef(全部进程);ps -ef | grep java(只看 java 相关的那几行) |
| 杀死系统进程的命令? | kill -9 xxxx(xxxx 是 ps 查出来的进程号 PID) |
完整的"重启服务"动作就是把上面几条串起来(以后改了代码重新打包上服务器,走的就是这一套):
ps -ef | grep java # ① 先找到旧进程的 PID(第二列就是)
kill -9 12345 # ② 把它杀掉(-9 强制杀)
java -jar tlias-web-management.jar # ③ 或者直接用 nohup 重新后台起来:
nohup java -jar tlias-web-management.jar &> tlias.log & # ④ 再确认一次在跑
ps -ef | grep java-9 是"强制杀死"的信号(进程来不及做收尾,但对这种"停掉重起"的场景正合适)。顺带一个和前端同样的道理:nginx 那边改了配置要 reload,这边改了代码要重打包、重上传、重起 jar——两个服务都不存在"改完自动生效"。
整条链路串一遍(部署完长什么样)
到这里两半都部署好了,把一次访问完整走一遍:
| 步骤 | 发生了什么 | 归谁管 |
|---|---|---|
| ① | 浏览器访问 http://192.168.100.128(不写端口就是 80) | — |
| ② | nginx 匹配 location /,从 /usr/local/nginx/html 取出 index.html 返回 | 前端(105 篇打包出来的静态页面) |
| ③ | 页面加载 assets/ 下的 js、css,同样是 nginx 发的 | 前端 |
| ④ | 页面脚本发 GET /api/depts 一类的请求,还是发给 80 的 nginx | 前端(baseURL: '/api',99 篇) |
| ⑤ | nginx 匹配 location ^~ /api/ → rewrite 摘掉 /api → proxy_pass 转给 localhost:8080 | 反向代理(同一套道理:59 篇) |
| ⑥ | 8080 上的 SpringBoot(java -jar 起的那个)处理请求 → 查服务器上的 MySQL → 返回 JSON | 后端(本篇后半段部署的 jar) |
| ⑦ | JSON 原路回到页面,渲染成表格 | 前端 |
三个"对不上就白干"的细节(照着排查就行):
| 现象 | 最可能的原因 |
|---|---|
| 页面打不开(浏览器一直转圈/超时) | 80 端口没在防火墙放行(108 篇的四步),或 nginx 没起来(ps -ef | grep nginx) |
| 页面能打开、数据是空的 | location ^~ /api/ 那段没配(/api/depts 被当成静态文件找不到 → 404),或者忘记 sbin/nginx -s reload |
| 页面能打开、接口报 502 Bad Gateway | 反向代理那一刻后端没人接——jar 没跑起来、或 proxy_pass 的端口和 jar 实际监听的端口(8080)对不上 |
| 接口报 404(转发出去之后) | rewrite 那一行没写/写错,后端收到的是带 /api 的路径(后端接口没有这个前缀) |
第 19 章到此结束(PPT 第 70 页)
第 70 页是一张空白页——第 19 章(Linux)到这里收官:从装系统、连远程、敲命令、装软件,到本篇把项目部署上线,一条完整的"上线之路"走完了。
不过这一路看下来也有个感受值得说一下:装 MySQL 那一长串命令、装 JDK 那几个包、配置一项项改——步骤多、容易错、换台机器还得重来一遍。下一章 Docker要解决的正是这个痛点:同一个 MySQL,用 Docker 一条命令就能跑起来。
小结
| 问题 | 答案 |
|---|---|
| 项目部署分哪两件事? | 前端项目部署(静态资源 → nginx 的 html 目录 + 配反向代理)与后端项目部署(jar → 上传 → 跑起来),两边都部署完用户才能从 80 端口访问到完整系统 |
| 前端静态资源传到哪? | nginx 的 html 目录——按 108 篇的安装位置就是 /usr/local/nginx/html;传的是资源里的文件(index.html、assets/、favicon.ico),不嵌套文件夹 |
conf/nginx.conf 里那段配置每行干什么? | listen 80(浏览器默认端口,用户访问入口);server_name localhost(域名匹配,单 server 块时按默认服务处理);client_max_body_size 10m(请求体上限);location / + root html/index/try_files(发前端页面、前端路由兜底);location ^~ /api/ + rewrite(摘掉 /api 前缀)+ proxy_pass http://localhost:8080(转发给后端) |
| 和第 7 章 Windows 那套什么关系? | 一个道理、一套配置:都是"静态托管 + /api 反向代理",只是 nginx 从 Windows 版换成服务器上装的(90 → 80)、后端从 IDEA 里的工程换成服务器上的 jar(都还在 8080) |
| nginx 三条命令? | 启动 sbin/nginx、停止 sbin/nginx -s quit、重新加载 sbin/nginx -s reload;在 nginx 安装目录里执行;改了配置必须 reload |
| 后端怎么打包、为什么先连数据库测通? | 在 maven 父工程执行 package 打出 jar;先把数据源改成服务器的 MySQL 并跑通、再打包——因为 jar 里带的是打包那一刻的配置 |
| jar 放哪、怎么跑? | 在 /usr/local 下建 tlias-app 目录、把 jar 传进去;java -jar xxxxxx.jar(前台跑,关窗口就停);nohup java -jar xxxxxx.jar &> tlias.log &(后台跑) |
nohup … &> tlias.log & 怎么读? | nohup 不受挂断影响(关窗口也不停)、&> 把输出重定向进 tlias.log、末尾 & 放到后台执行 |
| 怎么查进程、杀进程、重启? | ps -ef | grep java 找 PID → kill -9 PID 杀 → 再 nohup … & 重新起;这就是"重启服务"的完整动作 |
|、>、>> 分别是什么? | | 管道符(前一个命令的输出给后一个用);> 覆盖重定向;>> 追加重定向 |
| 页面能开但数据空 / 502 分别查什么? | 数据空 → /api 那段没配或没 reload(404);502 → 后端没起或 proxy_pass 端口不对;页面打不开 → 80 没放行或 nginx 没起 |
| 这一篇的实测情况? | 没有实测(需要真实 Linux 服务器 + 装好的环境);其中反向代理那一套在 第 7 章的 Windows 环境实测过,道理相同 |
相关
练习题
一、知识回顾(读完直接做下面的实践题)
- 部署分两件事(PPT 第 64 页):前端项目部署(打包好的静态资源交给 nginx)与后端项目部署(jar 在服务器上跑起来)——用户只访问服务器的一个入口(80)
- 前端部署三步(PPT 第 65 页):① 把
资料/06.项目部署/前端/页面资源里的静态资源上传到 nginx 的 html 目录 ② 改conf/nginx.conf配反向代理与路径重写 ③ 在 nginx 安装目录执行sbin/nginx(或改过配置用sbin/nginx -s reload) - 落点是哪个目录:
/usr/local/nginx/html(nginx 是用--prefix=/usr/local/nginx装的);传进去的是index.html、assets/、favicon.ico这些文件本身,不是把整个文件夹塞进去 - 配置里每行的意思:
listen 80(用户访问入口)、server_name localhost(域名匹配)、client_max_body_size 10m(请求体上限)、location / { root html; index index.html index.htm; try_files $uri $uri/ /index.html; }(发静态页面 + 前端路由兜底)、location ^~ /api/ { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://localhost:8080; }(摘掉/api前缀再转给后端) rewrite与proxy_pass的关系:/api/depts被rewrite改成/depts(后端接口路径本来就没有/api),再经proxy_pass转发到http://localhost:8080/depts- 和 第 7 章的关系:同一个道理、同一套配置——Windows 上那份
listen 90,服务器上这份listen 80;后端一个在 IDEA 里跑、一个用java -jar跑,都在 8080;localhost始终指"nginx 所在的那台机器" - nginx 三条命令(PPT 第 66 页):启动
sbin/nginx、停止sbin/nginx -s quit、重新加载sbin/nginx -s reload;都在 nginx 安装目录里执行;改配置必须 reload - 后端打包(PPT 第 68 页):在 maven 父工程执行 package 生命周期;打包之前先把数据源连上服务器数据库、先测试通过(jar 里带的是打包那一刻的配置)
- jar 放到哪:服务器
/usr/local下建目录tlias-app,把 jar 上传到/usr/local/tlias-app - 前台 vs 后台运行:
java -jar xxxxxx.jar占前台窗口(窗口关了服务就停);nohup java -jar xxxxxx.jar &> tlias.log &后台运行(nohup不受挂断影响、&>输出进日志、末尾&放后台) - 查看 / 杀死进程(PPT 第 69 页):
ps -ef、ps -ef | grep java看进程,kill -9 xxxx杀进程;重启服务 = 杀掉旧进程 + 重新 nohup 起 - Linux 特殊符号:
|管道符(前面命令的输出作为后面命令的输入,如ps -ef | grep java);>覆盖重定向、>>追加重定向(如echo 'Hello Linux' > 1.log) - 一次访问的完整链路:浏览器 → 80 的 nginx →
location /从 html 目录取页面 → 页面发/api/xxx给 80 →location ^~ /api/+rewrite+proxy_pass→ 8080 的 jar → MySQL → JSON 回页面 - 本轮实测边界:这一篇没有实测(需要真实 Linux 服务器与装好的环境);反向代理那一套在 第 7 章的 Windows 环境实测过,属于同一个道理
二、裸写题
- 提示(先自己想,实在想不出再点开)
一级 · 思路:nginx 是"静态服务器",它发页面时是拿某个目录当根去找文件的——那个目录写在配置里(
root html),而html是相对 nginx 安装目录的路径 二级 · 方法:安装位置是/usr/local/nginx(./configure --prefix定的),所以 html 目录就是/usr/local/nginx/html;root html找的就是它;传的是 dist/页面资源里面的文件,不能多套一层文件夹;访问http://192.168.100.128(80 可省),看到 Tlias 页面算成功 三级 · 骨架:① 目录:____/html;② 因为配置里写的是root ____,它是相对 nginx 的____目录;③ 放的是产物里面的文件(不带产物文件夹这一层);④ 访问http://____,看到____页面- 参考答案(做完再点开)
① 放的目录:/usr/local/nginx/html ② 为什么是这个目录: nginx 装的时候用了 ./configure --prefix=/usr/local/nginx, 所以 nginx 的"家"是 /usr/local/nginx; 配置里 location / 那段的 root 写的是 html(相对路径), 相对的正是 nginx 的安装目录 → 实际找的是 /usr/local/nginx/html。 ③ 层次问题: 传进去的必须是页面资源"里面的文件"——index.html、assets/、favicon.ico; 不能把整个文件夹塞进 html(那会变成 html/页面资源/index.html, 访问地址就得跟着带一层目录,和 http://192.168.100.128 对不上)。 另外它会替换掉 nginx 自带的欢迎页 index.html。 ④ 访问与判定: http://192.168.100.128 (80 是浏览器默认端口,可以不写) 看到 Tlias 的页面(不再是「Welcome to nginx!」)就成功。 打不开先查:nginx 起了没有(ps -ef | grep nginx)、80 放行了没有。检查点:① 路径写的是
/usr/local/nginx/html;② 能说清root html相对的是 nginx 安装目录;③ 知道是"产物里的文件"而不是整个文件夹;④ 访问地址是服务器 IP(80 可省)。- 用户访问服务器 IP(80 端口)打开页面;
- 静态资源在 nginx 安装目录的
html目录下,访问目录默认给index.html,前端路由刷新时不 404; - 页面里的请求形如
/api/depts,后端服务跑在同一台服务器的8080,接口路径不带/api; - 上传文件较大,请求体上限给 10m。 请写出完整的
server块,并给每行加注释说明在干什么。 (练习文件test_109_项目部署.md的题目2-2 里给了nginx.conf片段写作区。)
nginxserver { # 在这里补全 }- 提示(先自己想,实在想不出再点开)
一级 · 思路:一个
server块里写两条 location——一条管"其余所有请求"(发静态页面),一条管"/api/开头的请求"(改路径 + 转发) 二级 · 方法:端口是listen 80;、请求体上限client_max_body_size 10m;;静态那条是location / { root html; index index.html index.htm; try_files $uri $uri/ /index.html; };接口那条是location ^~ /api/ { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://localhost:8080; }三级 · 骨架:listen ____;↳server_name localhost;↳client_max_body_size ____;↳location ____ { root ____; index index.html index.htm; try_files $uri $uri/ /____; }↳location ^~ ____ { rewrite ^/api/(.*)$ ____$1 break; proxy_pass http://____:____; }- 参考答案(做完再点开)
nginxserver { listen 80; # 浏览器默认端口,用户的访问入口 server_name localhost; # 域名匹配(单 server 块时按默认服务处理) client_max_body_size 10m; # 允许的请求体最大 10MB(上传文件用) # 其余所有请求:从 html 目录取静态页面返回(前端页面) location / { root html; # 静态根目录(相对 nginx 安装目录) index index.html index.htm; # 访问目录时默认返回的文件 try_files $uri $uri/ /index.html; # 找不到就回 index.html(前端路由兜底) } # /api/ 开头的请求:摘掉前缀后转发给本机 8080 的后端 location ^~ /api/ { rewrite ^/api/(.*)$ /$1 break; # /api/depts → /depts proxy_pass http://localhost:8080; # 转给同机 8080 上的后端服务 } }自查四点:① 是两条 location(
/与^~ /api/),别写成一条;②rewrite的替换目标是/$1(以/开头),这样/api/depts才会变成/depts;③proxy_pass只写到主机端口、不追加路径;④ 改完这个文件必须sbin/nginx -s reload才生效。- nginx
listen 80; location / { root html; index index.html index.htm; try_files $uri $uri/ /index.html; } location ^~ /api/ { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://localhost:8080; }- 提示(先自己想,实在想不出再点开)
一级 · 思路:分三层读——"服务听在哪个端口""哪些请求归哪条 location 管""对请求做了什么"(做的一般是两步:改路径、换目的地) 二级 · 方法:
listen是端口;location /+root html决定页面从/usr/local/nginx/html取、try_files是前端路由兜底;location ^~ /api/是前缀匹配;rewrite用正则把/api摘掉((.*)捕获、$1引用);proxy_pass把请求交给localhost:8080三级 · 骨架:① 访问 IP → 匹配location ____→ 从____目录取____;②/api/depts→rewrite成____→ 转给http://____:____;③ 没有 rewrite → 后端收到____,返回____;④ 后端没起 → 转发没人接,nginx 返回____- 参考答案(做完再点开)
逐行:
listen 80;——这个服务监听 80 端口(浏览器默认 HTTP 端口),也就是用户访问的入口;location / { … }——其余所有请求(不是/api/开头的)走这条;root html;——静态根目录,html相对 nginx 安装目录,实际是/usr/local/nginx/html;index index.html index.htm;——访问目录时默认返回index.html;try_files $uri $uri/ /index.html;——先按路径找文件,找不到就回index.html(前端路由兜底,刷新页面不 404);
location ^~ /api/ { … }——/api/开头的请求走这条(^~前缀匹配,命中后不再试正则);rewrite ^/api/(.*)$ /$1 break;——把/api前缀重写掉:/api/depts→/depts;proxy_pass http://localhost:8080;——把(重写后的)请求转发给本机 8080 的后端服务。 四个回答: ① 访问http://192.168.100.128→ 匹配location /→ nginx 从/usr/local/nginx/html取出index.html返回; ②/api/depts→ 匹配location ^~ /api/→rewrite成/depts→proxy_pass转给http://localhost:8080/depts(同机 8080 上的后端 jar); ③ 没有rewrite→ 转发出去还是/api/depts,而后端接口是/depts(没有/api前缀)→ 404,页面数据空; ④ 后端没启动 → 8080 上没人监听,代理转发失败 → nginx 返回 502 Bad Gateway。 一句话:页面归 nginx 自己发,/api归后端——nginx 在中间当了"换门牌号 + 跑腿"的角色。
- 提示(先自己想,实在想不出再点开)
一级 · 思路:五站——改配置并测通 → 打包 → 传上去 → 先前台跑一次确认能起 → 再改成后台跑;"后台"那一行要解决三个问题:不被挂断、输出去哪、怎么立刻返回 二级 · 方法:打包用 maven 父工程的 package;jar 放
/usr/local/tlias-app(先mkdir);前台是java -jar xxxxxx.jar(关窗口就停);后台是nohup java -jar xxxxxx.jar &> tlias.log &;查进程ps -ef | grep java,杀进程kill -9 PID三级 · 骨架:① 先把application.yml的数据源改成____并测通;② 父工程执行____;③mkdir /usr/local/____→ 上传 jar;④java -____ xxxxxx.jar;⑤____ java -jar xxxxxx.jar &> ____ &;⑥ps -ef | grep ____、kill -____ PID- 参考答案(做完再点开)
① 打包前必须做的事: 把工程的数据源配置改成服务器上的 MySQL(192.168.100.128:3306、root/1234), 并在服务器上执行 tlias.sql 建好库表,先在本地连服务器数据库跑通、测过。 原因:jar 里打进去的是"打包那一刻"的配置——先打包再改, 等于抱着一个连不上数据库的 jar 上服务器(启动就报错)。 ② 打包: 在 maven 父工程上执行 package 生命周期(IDEA 的 Maven 面板双击 package)。 产物:可执行的 jar 包(课程资料里那份叫 tlias-web-management.jar)。 ③ 放到哪: mkdir /usr/local/tlias-app 把 jar 上传到 /usr/local/tlias-app(FinalShell 上传) ④ 前台跑一次: cd /usr/local/tlias-app java -jar tlias-web-management.jar 现象:日志刷在屏幕上(能看到 Tomcat started on port 8080 / Started ...Application), 窗口被占着、不能关——"窗口关闭服务也就停了"。确认没问题后 Ctrl+C 停掉。 ⑤ 后台运行(推荐): nohup java -jar tlias-web-management.jar &> tlias.log & · nohup —— 不受终端挂断影响(关掉 FinalShell 窗口服务照跑) · &> tlias.log —— 标准输出和标准错误都重定向进 tlias.log(日志留痕) · 末尾 & —— 放到后台执行,命令立刻返回 ⑥ 查看 / 停止 / 重启: ps -ef | grep java # 找到 java 进程的 PID(第二列) kill -9 PID # 强制杀掉旧进程 nohup java -jar tlias-web-management.jar &> tlias.log & # 重新后台起 (改了代码就是"重新打包 → 重新上传 → 杀掉旧进程 → 重新 nohup 起")检查点:① 说清"先改数据库配置、测通、再打包"以及为什么;② 打包命令是父工程的 package;③ 目录是
/usr/local/tlias-app;④ 后台那一行三个部分都能解释;⑤ 知道ps -ef | grep和kill -9的用法。- 提示(先自己想,实在想不出再点开)
一级 · 思路:按"请求走到哪一站失败"来定位——浏览器到 nginx、nginx 到静态文件、nginx 到后端、后端到接口路径,四站四问 二级 · 方法:打不开先看 80 端口放行与 nginx 进程;数据空看
/api那段配置有没有、有没有-s reload;502 看后端进程与proxy_pass的端口;404 看rewrite有没有把/api前缀摘掉 三级 · 骨架:① 查____放行 +ps -ef | grep ____;② 查location ^~ ____是否配置/是否sbin/nginx -s ____;③ 查ps -ef | grep ____与proxy_pass的____;④ 查____那一行写没写对- 参考答案(做完再点开)
① 完全打不开(连页面都没有):最可能是 80 端口没在防火墙放行,或 nginx 没起来。先查:
firewall-cmd --zone=public --list-ports看 80 在不在、ps -ef | grep nginx看进程(必要时systemctl status firewalld)。 ② 页面能开、数据空:最可能是location ^~ /api/那段没配(于是/api/depts被当成静态文件去找 → 404),或者配了但没有sbin/nginx -s reload(配置没生效)。先查:conf/nginx.conf里有没有那段、改完有没有 reload。 ③ 502 Bad Gateway:说明 nginx 转发出去了但没人接——后端 jar 没跑起来,或proxy_pass的端口和 jar 实际监听的端口(8080)不一致。先查:ps -ef | grep java、tail -f tlias.log看后端启动日志。 ④ 转发出去之后 404:路径对不上——rewrite那一行没写或写错,后端收到的是带/api的路径,而它的接口是/depts(没有/api前缀)。先查:配置里rewrite ^/api/(.*)$ /$1 break;在不在、$1前有没有/。 顺带记一条顺序:排查从外往里(防火墙 → nginx → 静态文件 → 代理 → 后端 → 数据库),哪一站断了一目了然。
三、综合题
- 先梳理分工:哪一半归 nginx、哪一半归 jar;用户最终访问的是哪个地址、哪几个端口;
- 准备后端:把工程数据源改成服务器的 MySQL → 在服务器上执行
tlias.sql建库表 → 本地连服务器数据库测通 → 父工程执行package打出 jar; - 部署后端:
mkdir /usr/local/tlias-app→ 上传 jar → 先java -jar前台跑一次确认能起(看到 8080 启动日志)→ 改成nohup … &> tlias.log &后台跑 →ps -ef | grep java确认; - 部署前端:把页面资源(
index.html、assets/、favicon.ico)上传到/usr/local/nginx/html; - 配 nginx:改
conf/nginx.conf的server块——listen 80、client_max_body_size 10m、location /(root html+index+try_files)、location ^~ /api/(rewrite+proxy_pass http://localhost:8080); - 放行端口 + 起服务:防火墙放行 80(四步:查状态 →
--add-port=80/tcp --permanent→--reload→--list-ports);nginx 第一次sbin/nginx启动、改过配置用sbin/nginx -s reload; - 验证整条链路:浏览器访问
http://192.168.100.128→ 页面出来 → 点开有数据的页面(如员工管理)→ 表格渲染出数据(说明/api那一路也通了); - 收尾:把"页面能开""数据能出"分别对应到哪一段配置说一遍,并想一遍四种故障(打不开 / 数据空 / 502 / 转发后 404)各自查哪里。
- 提示(先自己想,实在想不出再点开)
一级 · 思路:整条链路是"一个入口、两个服务"——入口是 80 的 nginx;两个服务是 nginx 自己和 8080 的 jar。清单按"先后端、再前端、最后入口"的顺序做最顺(后端先起来,代理转过去才有人接) 二级 · 方法:后端 = 改数据源 +
package+/usr/local/tlias-app+nohup java -jar … &> tlias.log &;前端 = 页面资源 →/usr/local/nginx/html;入口 =conf/nginx.conf的server块两段 location + 防火墙放行 80 +sbin/nginx/-s reload三级 · 骨架:① 后端打 jar(____生命周期,先改____并测通);② 后端跑起来(nohup java -jar ____ &> ____ &);③ 前端传____/html;④ 配 nginx(listen ____/location ^~ ____/proxy_pass http://____:____);⑤ 放行 80(--____=80/tcp --permanent+--reload);⑥ 访问http://____,页面 + 数据都出来了才算成功- 参考答案(做完再点开)
清单:Tlias 部署到 Linux 服务器(PPT 第 63~70 页) 【0】先画清楚分工 · 浏览器 → http://192.168.100.128(80 端口) · 80 上的 nginx:自己发前端静态页面 + 把 /api 请求转给 8080 · 8080 上的 jar:处理接口、连服务器上的 MySQL 【1】后端:准备与打包 · 改工程数据源 → jdbc:mysql://192.168.100.128:3306/tlias,root/1234 · 服务器 MySQL 上执行 tlias.sql 建库建表 · 本地连服务器数据库跑通、测过(这一步不能跳:jar 带的是打包那刻的配置) · maven 父工程执行 package → 得到 tlias-web-management.jar · 确认成功:本地起服务能查到数据 【2】后端:上传并跑起来 · mkdir /usr/local/tlias-app · 上传 jar 到 /usr/local/tlias-app · 先前台试一次:java -jar tlias-web-management.jar (看到 Tomcat started on port 8080 / Started ...Application)→ Ctrl+C 停掉 · 后台运行: nohup java -jar tlias-web-management.jar &> tlias.log & · 确认成功:ps -ef | grep java 能看到这个进程; tail -f tlias.log 能看到启动日志 【3】前端:放静态资源 · 把页面资源里的文件(index.html、assets/、favicon.ico) 上传到 /usr/local/nginx/html · 确认成功:/usr/local/nginx/html 下直接能看到 index.html 【4】入口:配 nginx · 编辑 /usr/local/nginx/conf/nginx.conf,http { } 里的 server 块: server { listen 80; server_name localhost; client_max_body_size 10m; location / { root html; index index.html index.htm; try_files $uri $uri/ /index.html; } location ^~ /api/ { rewrite ^/api/(.*)$ /$1 break; proxy_pass http://localhost:8080; } } · 确认成功:改完执行 sbin/nginx -s reload(第一次是 sbin/nginx) 【5】放行端口 · systemctl status firewalld (或 firewall-cmd --state) · firewall-cmd --zone=public --add-port=80/tcp --permanent · firewall-cmd --reload · firewall-cmd --zone=public --list-ports → 看到 80/tcp · (8080 不用对外放行:nginx 在服务器内部访问它) 【6】验证 · 浏览器 http://192.168.100.128 → Tlias 页面出来(说明 location / 那一路通) · 打开员工管理/部门管理 → 表格有数据(说明 /api 那一路也通) · 服务重启:kill -9 旧 PID + 重新 nohup(后端); 改配置后 sbin/nginx -s reload(前端) 【7】四种故障对号入座 打不开 → 80 放行 / nginx 进程 页面能开数据空 → /api 那段没配或没 reload(404) 502 → 后端没起 / proxy_pass 端口不对 转发后 404 → rewrite 没写对(/api 前缀没摘掉)检查点:① 顺序是"后端先起 → 前端资源就位 → 配 nginx → 放行端口";② 每一站都有"怎么确认成功";③ 两段 location 一字不错,尤其
rewrite的/$1与proxy_pass的localhost:8080;④ 能说清"页面归 location /,数据归 location ^~ /api/",四种故障会定位;⑤ 与 第 7 章那套 Windows 联调对得上。
