前后端分离项目本地联调跑得欢,一上服务器就各种幺蛾子——要么接口 502,要么刷新页面 404,要么前端白屏什么都打不开。这种经历我相信不少人都遇到过。网上讲宝塔面板部署的教程不少,但多数只讲了“把文件传上去、点几下按钮”,至于为什么这么配、跨域是怎么被解决的、502 到底是谁的问题,基本没讲透。这篇文章我就按自己实际部署 SpringBoot + Vue 前后端分离项目的流程,把宝塔面板部署上线的完整链路拆开讲,从架构规划、打包自检、Nginx 反向代理到 SSL 配置和故障排查,尽量做到“照做就能成,报错也能自己查”。
先说清楚这套东西适合谁看:项目用的是 SpringBoot 做后端接口、Vue 做前端页面,部署目标是云服务器上的宝塔面板系统。你可能是自己练手项目的学生,也可能是刚接手公司部署任务的新手运维。只要你手里有这样一个前后端分离项目,并且准备用宝塔把线上环境跑起来,这篇文章应该能省下你不少瞎折腾的时间。
1. 动手之前先把部署架构想清楚:三种文件放哪里、端口怎么规划
很多人一上来就急着打包、上传,结果后端没起、前端没配、Nginx 写成一锅粥。部署前后端分离项目,第一步不是敲命令,而是把架构在脑子里理顺。我见过太多部署失败案例,最后根因都是“没想清楚谁跟谁通信”。
1.1 前后端分离部署的本质是“两个进程加一个入口”
部署模型其实非常简单,拆开看就三块:
- 前端(Vue):构建后是一堆静态文件(HTML、JS、CSS、图片),本身不需要运行环境,只需要一个能托管静态文件的 Web 服务器。我们用的是 Nginx。
- 后端(SpringBoot):一个可执行的 jar 包,内部自带 Tomcat,通过
java -jar启动后监听某个端口提供接口服务。 - Nginx 的两重身份:作为 Web 服务器托管前端静态文件,同时作为反向代理把接口请求转发给后端 jar。
说得直白点,浏览器打开你的域名,Nginx 先把首页 HTML 和 JS 资源发给它;浏览器执行 JS 后开始发 Ajax 请求,请求路径是/api/xxx,Nginx 一看这个前缀,就转发给127.0.0.1:8080的 SpringBoot 进程。整个过程浏览器只知道自己在访问你的域名,压根不知道后端的存在。
1.2 端口规划与放行清单
前后端分离部署最容易忽略的就是端口。默认规划可以参考下面这张表,具体项目按实际调整:
| 组件 | 默认端口 | 作用 | 是否对外开放 |
|---|---|---|---|
| Nginx | 80 / 443 | 托管前端、反向代理 | 80 和 443 对外开放 |
| SpringBoot | 8080 | 后端接口服务 | 不对公网开放,只允许本机访问 |
| MySQL | 3306 | 数据库 | 强烈建议只允许本机访问 |
| 宝塔面板 | 8888 | 面板管理(不同宝塔版本有差异) | 仅限你管理时访问,用完可关 |
这里有个很多人踩过的坑:云服务器厂商的安全组规则和宝塔面板的防火墙是两套独立的东西,必须同时放行。你宝塔里放行了 80 端口,但云服务商安全组没加规则,外部照样访问不了。反过来也一样。所以部署第一步,先把云服务商控制台的安全组 80/443 放行,再在宝塔面板的“安全”菜单里放行对应端口。
1.3 目录规划
服务器上的目录建议一次性规划好,不要东一个西一个。我用的是宝塔默认站点目录下的项目名分目录方式,例如:
/www/wwwroot/你的项目名/ ├── dist/ # Vue 打包产物 ├── server/ # jar 包、启动脚本、日志文件 └── logs/ # (可选)单独放 nginx 或后端日志目录规划的意义在于:出现问题时你能快速定位文件位置,写 Nginx 配置时 root 路径也不会写错。后面所有配置都基于这个目录结构展开,你可以按自己的习惯微调,但前后端分开放、别把 jar 直接扔在 dist 里这一点务必坚持。
2. 前端 Vue 项目构建打包前的三个检查点
前端打包看似一条npm run build命令解决,但实际把 dist 丢到服务器上跑起来后,最先出问题的往往就是前端。
2.1 环境准备与依赖安装
本地先确认 Node.js 版本和包管理器类型。Vue 3 + Vite 项目通常要求 Node 14 以上,低版本会直接构建报错。建议先用一个干净目录拉取项目代码,再执行依赖安装:
# 查看当前 Node 版本,尽量 >= 16 node -v # 安装依赖,尽量用 npm ci 锁定依赖版本,避免 package-lock 变更 npm ci # 也可以使用 pnpm,速度更快 pnpm install我个人习惯在部署前删掉本地node_modules重新安装一遍,因为长期开发中依赖可能变得很脏,重新安装能规避很多“本地行、别人不行”的灵异问题。另外,构建机上打包和服务器上打包结果理论上一致,但为了速度,通常建议在自己电脑或专门的构建服务器上打包,然后把 dist 上传到服务器。如果你是直接把代码 git clone 到服务器上用宝塔终端构建,也不是不行,但服务器内存小于 1GB 时打包很容易被 kill 掉,这时候还是本地打包更省心。
2.2 接口地址配置:从 axios baseURL 到环境变量
前端代码里请求接口时写的地址是整个部署的核心。开发环境下,很多人用 Vite 代理解决跨域,请求路径写的是相对路径/api/login,代理规则把/api转发到http://localhost:8080。这种写法到了生产环境其实是最省事的——因为生产环境我们同样会用 Nginx 把/api转发到后端服务,前端代码一行都不用改。
但如果你的代码在开发时写死了http://localhost:8080这样的绝对地址,上线前必须改成环境变量控制的方式。推荐在项目根目录创建.env.production文件(Vite 项目)或使用相应的环境变量机制:
# .env.production VITE_API_BASE_URL=/api然后在封装 axios 的地方读取它:
const service = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL || '/api', timeout: 15000 })这么做的好处是,前端构建产物里所有请求都是同源的,浏览器不会产生跨域问题,后续接口都走 Nginx 转发,后端也不需要为了部署环境单独开 CORS。这一点我后面讲跨域原理时会再展开。
2.3 构建命令与 dist 产物自检
执行构建命令前,重点检查两处配置:Vite 的base配置和路由 history 模式。
如果是 Vite 项目,默认base是/,通常不需要改。但如果你把前端部署到某个子路径下(比如https://域名/admin),那base就要对应修改。多数全站部署的场景保持/即可。
createWebHistory这种 history 路由模式,在开发环境没问题,但部署到 Nginx 后刷新页面容易 404,需要配合 Nginx 的try_files配置,后面 Nginx 部分会提到。
构建命令按项目而定:
# Vite 项目 npm run build # Vue Cli 项目 npm run build:prod构建完成后检查 dist 目录,正常应该生成index.html和一个带 hash 的 js/css 目录。这时候在本地用简单的静态服务器预览一下产物:
# 如果本机有 python3 cd dist python3 -m http.server 8081然后浏览器打开http://localhost:8081,看页面是否正常渲染、接口请求路径是否是/api开头。这时候接口当然会报错,因为本地没有后端,但你至少能确认静态资源引用路径没毛病。如果预览时控制台一堆资源 404,多半是base配错了,先解决再上传。
3. SpringBoot 后端打包、数据库准备与进程管理
前端产物是静态文件,扔上去就能访问;后端则需要老老实实处理环境差异。后端部署的复杂度主要不在打包,而在于配置文件区分、启动方式管理和数据库迁移。
3.1 打包前必须检查的三类配置
SpringBoot 项目通常有application.yml和多个 profile 文件。我强烈建议你至少准备一套生产环境专用的 profile,也就是application-prod.yml。里面重点检查三类内容:
第一是数据库连接。本地一般连的是localhost,服务器上要改成 MySQL 的实际地址和端口。如果 MySQL 和 jar 在同一台服务器,可以写127.0.0.1:3306,不要把数据库密码写在配置里并被 git 仓库公开,生产环境建议用环境变量覆盖。配置可以这样写:
spring: datasource: url: jdbc:mysql://127.0.0.1:3306/your_db_name?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai username: your_db_user password: your_db_password第二是服务端口。SpringBoot 默认 8080,如果你改了端口,务必记住后面 Nginx 的proxy_pass要和它保持一致。端口不要用 80,因为 80 要给 Nginx 用。
第三是文件上传和日志路径。如果项目里有上传功能,上传目录在本地可能是相对路径,部署后必须改成服务器上的绝对路径,否则文件会写到启动目录下的随机位置,重启后还可能丢。日志路径也要显式配置,方便后面排查问题。
3.2 Maven 打包与本地启动验证
打包命令很简单,但有几个参数值得注意:
# 跳过测试、指定生产 profile 执行打包 mvn clean package -DskipTests -P prod打包后在target目录下会生成 jar 文件,比如demo-0.0.1-SNAPSHOT.jar。建议在本地先执行一次生产配置启动,确认配置没写错:
java -jar target/demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod本地如果能正常启动并连上数据库,再传到服务器。如果本地都无法启动生产配置,那问题出在配置本身,别指望到了服务器上就能神奇变好。
服务器上还需要确认 Java 环境。宝塔面板的软件商店里有 Java 项目管理器(不同版本可能叫法不同),但更通用的方式是自己安装 OpenJDK:
# CentOS / 宝塔常用系统环境示例 yum install -y java-11-openjdk java -version如果你的项目用了 Java 17 甚至 21 的特性,记得安装对应版本,版本不对启动时会直接报 UnsupportedClassVersionError,一眼就能看出来。
3.3 启动脚本:别用裸 java -jar
有经验的部署者都会写启动脚本,而不是直接java -jar命令行跑。原因很简单:你需要能暂停、能重启、能把日志落到文件里,裸命令放到 SSH 终端里,终端一关进程就没了。
下面是一个简洁但实用的启动/停止脚本,放在 server 目录下:
#!/bin/bash # start.sh APP_NAME=你的jar包名.jar LOG_FILE=/www/wwwroot/你的项目名/server/app.log nohup java -jar $APP_NAME \ --spring.profiles.active=prod \ --server.port=8080 \ > $LOG_FILE 2>&1 & echo "PID: $!" echo $! > app.pid停止脚本:
#!/bin/bash # stop.sh if [ -f app.pid ]; then PID=$(cat app.pid) kill -9 $PID 2>/dev/null rm -f app.pid echo "应用已停止" else pkill -f '你的jar包名.jar' echo "已按进程名停止" fi有了这两个脚本,后续更新发布就是“停止、替换 jar、启动”三个动作,十分钟搞定。启动后第一时间看日志:
tail -f /www/wwwroot/你的项目名/server/app.log看到类似Started DemoApplication in 5.32 seconds或者Tomcat started on port(s): 8080就说明后端已经起来了。
3.4 数据库迁移与初始化
如果你用的是 MySQL,部署前一定要在宝塔面板里新建一个数据库,并把本地的表结构和初始数据导入。这一步可以等到了宝塔面板软件准备环节一起做,但逻辑上属于后端准备的一部分,别等到 jar 启动后才想起数据库没建。导入方式很简单:宝塔的 phpMyAdmin 里选择数据库,再点击“导入”选择.sql文件即可。如果数据量较大,用命令行导入更稳妥:
mysql -u用户名 -p密码 数据库名 < 本地导出的.sql文件注意编码问题:导入前确认 SQL 文件本身是 UTF-8 编码,导入后在 MySQL 里用show variables like 'character%'看一下,避免出现中文乱码。
4. 宝塔面板侧准备:Nginx、MySQL 与站点目录
后端 jar 和前端 dist 都准备好了,接下来才进入宝塔面板的正题。宝塔版本之间的界面略有差异,但核心操作路径大致相同。
4.1 软件商店安装 Nginx 与 MySQL
打开宝塔面板,左侧菜单进入“软件商店”,在运行环境分类下安装 Nginx 和 MySQL。版本选择建议:
| 软件 | 推荐版本 | 理由 |
|---|---|---|
| Nginx | 1.22+ | 稳定,官网长期维护的 mainline 版本即可 |
| MySQL | 5.7 或 8.0 | 根据本地开发版本选,5.7 和 8.0 的 SQL 兼容性差异要注意 |
| Pure-FTPd | 需要时安装 | 用于文件传输,宝塔文件管理器也能替代 |
MySQL 安装时间比较长,可以先去把其他操作做了。装完 MySQL 后,记得在“数据库”菜单里新建一个数据库,并创建一个专用账号,账号权限只分配这个库,不要直接给 root 远程权限。这是安全底线,生产环境尤其重要。
4.2 创建站点与绑定域名
在宝塔“网站”菜单里点击“添加站点”,填上你的域名(比如www.example.com),PHP 版本选择“纯静态”,因为在前后端分离架构下,Nginx 只需要托管静态文件,不需要处理 PHP。数据库选项如果已经有库就选择不创建。
站点创建完成后,宝塔会自动生成一个站点根目录,通常位于/www/wwwroot/你填写的域名/。这里我建议把前端 dist 内容直接上传到这个目录,或者像我目录规划中那样,在站点根目录下分开管理。
等等,这里要说清楚:站点的根目录就是给 Nginx 用的 root 目录,所以前端文件应该放在这里。后端 jar 可以放在站点根目录下的子目录 server 里,也可以单独放/home/app/,看你习惯。核心是 Nginx 的 root 指向必须是 dist 文件所在路径。
4.3 上传文件:宝塔文件管理器最省事
上传 dist 和 jar,我用得最多的是宝塔自带的文件管理器,不需要额外配置 FTP 账号。把 dist 整个目录压缩成 zip 上传,然后再在服务器上解压。这样做比一个个上传几百个小文件快得多。
# 在站点根目录下解压 cd /www/wwwroot/你的项目名 unzip dist.zipjar 包也一样,直接传到 server 目录。上传后别急着启动,先改权限:
chmod +x start.sh stop.sh chmod 755 你的jar包名.jar5. 跨域问题的本质与 Nginx 反向代理配置
这是全文最核心的部分。很多人把“前后端分离部署”和“跨域”搅在一起,一看到浏览器控制台报 CORS 错误就跑去后端加注解、加过滤器,其实部署阶段绝大多数跨域问题应该是通过 Nginx 反向代理解决的。
5.1 为什么本地开发才需要跨域
浏览器有个同源策略:协议、域名、端口三者完全一致才算同源。本地开发时,Vue 开发服务器跑在 5173(Vite 默认)或 8080,SpringBoot 跑在 8080,端口不同,所以浏览器认为这是跨域请求。这时候要么后端开 CORS,要么前端配代理。开发阶段最常见的做法是 Vite 代理:
// vite.config.js server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } }这里changeOrigin: true很关键,它让代理转发时把请求的 Host 头改成目标地址,后端才不会因为 Host 校验拒绝请求。
5.2 生产环境为什么不需要前端跨域了
生产环境部署后,浏览器访问的是你的域名。前端页面从你域名加载,接口请求也发到你域名下的/api/xxx,浏览器看到的请求是同源的,压根不会触发同源策略,所以前端不需要任何跨域配置。
真正把请求转发给后端的是 Nginx,而 Nginx 这种服务端到服务端的转发不涉及浏览器同源策略,属于服务端代理,不叫跨域。这也是我前面强调前端请求路径要写成/api的原因——如果写成了http://127.0.0.1:8080,浏览器依然会把它当跨域请求处理,而且这个地址是内网地址,跑到用户浏览器里直接访问不了。
5.3 一份可复用的 Nginx server 配置
域名解析到服务器后,在宝塔的“网站”列表里点击对应站点,进入“配置文件”编辑 Nginx 配置。一份能跑通的典型配置如下:
server { listen 80; # 改成你自己的域名 server_name www.example.com; # 前端 dist 目录 root /www/wwwroot/你的项目名/dist; index index.html; client_max_body_size 50m; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }这个配置里有两个精髓。第一个是location /里的try_files $uri $uri/ /index.html;——没有它,vue-router 的 history 模式刷新页面就会 404,因为 Nginx 找不到/login这样的真实路径,必须回退到 index.html 让前端路由接管。
第二个是location /api/里的proxy_pass http://127.0.0.1:8080;注意末尾没有斜杠。这里有无数人踩坑。规则是这样的:
- 如果
proxy_pass后面没有 URI 路径(也就是没有斜杠),转发时会保留原始请求的完整 URI。比如/api/user/list转发成http://127.0.0.1:8080/api/user/list。 - 如果
proxy_pass末尾带了/,比如http://127.0.0.1:8080/,则匹配到的前缀/api/会被替换成/。比如/api/user/list会被转发成http://127.0.0.1:8080/user/list。
所以到底用哪种,取决于后端接口路径是否带/api前缀。多数情况下后端接口本身就是@RequestMapping("/api/user")这种写法,那 Nginx 就保持proxy_pass不带斜杠,原样转发。如果你的 SpringBoot 接口没有/api前缀,而前端统一用/api请求,那就需要proxy_pass末尾带斜杠进行路径前缀剥离。这个要结合项目实际,不要在网上看到一个配置就复制乱改。
5.4 后端到底还开不开 CORS
部署阶段由 Nginx 反代解决跨域了,那后端@CrossOrigin或全局 CORS 配置是否要删掉?
我的建议是留着无妨,但要知道它不起主要作用了。实际场景里,你无法保证所有流量都走自己的 Nginx,比如调试阶段或第三方系统直接调用后端接口时,CORS 配置依然有意义。但要注意:如果后端开了非常宽泛的 CORS(allowedOriginPatterns("*")),并且没有妥善处理预检请求,某些情况下反而会让浏览器出现奇怪的双重跨域行为。上线后如果遇到这类问题,后端服务日志里会有 OPTIONS 请求记录,据此排查即可。最干净的方式还是前端全走/api相对路径,后端 CORS 配置保持严格收紧的基本款或干脆关闭。
6. 上传产物、配置 SSL 与正式上线
配置写好后,接下来就是真刀真枪上线了。这里顺序很重要:先启动后端,再操作 Nginx 和 SSL,避免线上出现“页面能开但接口全挂”的尴尬。
6.1 启动后端与流量验证
回到 server 目录,执行:
./start.sh等几秒后看日志确认启动成功,然后在服务器本地用 curl 验证接口是否可用:
curl -v http://127.0.0.1:8080/api/health 2>&1 | head -20这里用小接口或者健康检查接口测试即可。如果在服务器本机 curl 都失败,那基本是后端没起来,跟 Nginx 无关,先不要去改网络配置。
6.2 Nginx 配置生效与常见失败点
修改 Nginx 配置后需要验证语法并重载:
nginx -t nginx -s reload如果nginx -t报错,通常是配置文件里有语法问题,比如缺少分号、括号没闭合、server_name 后面少了域名。宝塔面板里修改的配置文件在修改时会自动备份,出错时可以点“还原”回到之前状态。
重载后,在浏览器里访问你的域名。此时应该能打开前端首页,接口也通了。如果页面打不开,先确认域名是否解析成功:
ping 你的域名 nslookup 你的域名解析不 success 就先解析,不要折腾 Nginx。
6.3 配置 SSL 证书并强制 HTTPS
现在主流浏览器对无 HTTPS 站点越来越不友好,所以 SSL 基本是上线必做项。宝塔提供了免费的 Let‘s Encrypt 证书申请,操作路径是:站点设置 → SSL → Let’s Encrypt,勾选域名后申请。申请前提是域名已经解析到这台服务器,且 80 端口可访问,因为证书申请过程需要验证域名所有权。
证书签发成功后,宝塔会自动生成 443 端口的 HTTPS 配置。建议在 SSL 面板里打开“强制 HTTPS”,这样 HTTP 请求会自动 301 跳转到 HTTPS。跳转后注意后端接口同样会被跳转,而接口作为 XHR 请求处理 301 的方式和普通页面不一样,某些情况下会引发请求失败。遇到这种问题,检查 Nginx 里的跳转配置是否合理,或者干脆只对location /跳转、location /api/保持 80 端口放行,再从应用层强制要求 HTTPS。但大多数简单场景直接“强制 HTTPS”即可,先跑通再优化。
6.4 前端静态文件缓存与更新策略
上线后修改前端代码是常态,但经常出现“改了代码,线上还是旧页面”的困扰。原因是浏览器缓存了旧的 JS、CSS。Vue 构建产物的文件名通常带 hash,内容变了文件名会变,所以理论上不会缓存旧文件。真正容易缓存的是index.html本身。如果它被缓存了,浏览器还是加载旧的文件名,页面却显示新的文件名列表,就会白屏。
应对方法是在 Nginx 里对静态资源设置合理的缓存策略,对 index.html 设置不缓存或短缓存:
location = /index.html { add_header Cache-Control "no-cache, no-store, must-revalidate"; } location ~* \.(js|css|png|jpg|gif|svg|woff2?)$ { expires 30d; add_header Cache-Control "public, immutable"; }这样平时静态资源可以放心让浏览器缓存,发布时只要更新了带新 hash 的文件,index.html 每次都会回源检查,不会出现旧文件残留问题。
7. 上线后的验证与故障排查:502、404、白屏一条链查到底
上线不是终点,验证才是。就算按我的流程走,项目第一次部署也一定有报错。下面把这些年遇到的高频故障整理成排查链路,按步骤走,基本能把问题定位到具体层。
7.1 分层排查思维
我排查问题从来不看表面症状,而是先确定“问题出在前端、Nginx 还是后端”这三层中的哪一层。判断方法最有效的是按浏览器工具分:
- 页面能打开、接口报 502 → 问题在后端或 Nginx 到后端的链路
- 页面刷新 404 → 问题在 Nginx 的 try_files 配置(前端路由)
- 页面白屏、控制台资源 404 → 问题在静态资源路径(base 配置或 dist 未正确上传)
记住这个归类,往下看会有豁然开朗的感觉。
7.2 接口 502 Bad Gateway:从几个方向并行排查
502 是最常见的部署错误,字面意思是“网关收到了但得不到有效响应”,放在 Nginx 语境下就是“Nginx 把请求转发给 127.0.0.1:8080,但对方没接住”。排查方向如下:
第一步,确认后端进程仍存活:
ps -ef | grep java ss -tlnp | grep 8080如果 Java 进程不在了,看日志找崩溃原因。常见原因是服务器内存不足,SpringBoot 启动过程中被系统终止,或者nohup启动时没有重定向日志,输出丢失后进程被终端挂断。我遇到过最经典的问题是服务器只有 1GB 内存,Java 默认堆内存设置导致 OOM,方案是加一个-Xmx512m参数限制堆大小,保证系统有余量。
第二步,在服务器本机模拟一次转发:
curl http://127.0.0.1:8080/api/health如果这一步也 502,说明 Nginx 配置的proxy_pass和实际 jar 监听端口不一致,或者后端没有监听到 127.0.0.1 而是监听了别的主机名。SpringBoot 默认监听0.0.0.0,一般没问题。注意检查是否配置了server.address导致异常。
第三步,检查 Nginx 错误日志:
tail -f /www/wwwroot/你的项目名/logs/error.log这里能看到具体的 upstream 连接失败原因,比如连接被拒绝、超时等。看到日志再动手,比盲目改配置高效得多。
7.3 刷新页面 404:经典 history 路由问题
现象:首页能打开,但你点点点进到/detail页面再刷新,出现 404。这几乎可以断定是 Nginx 缺少try_files。解决方法就是前面配置里的那行:
location / { try_files $uri $uri/ /index.html; }加上后刷新页面会重新加载 index.html,前端路由接管后再匹配/detail,页面正常显示。注意后端如果也有/路径拦截,别让location /的 try_files 和后面location /api/产生冲突,二者路径前缀不同,互不干扰。
7.4 接口跨域报错仍然出现:先看请求实际发到了哪里
有时候部署完接口返回 CORS 错误,别急着给后端加配置。先打开浏览器开发者工具,看 Network 里请求的实际 URL:
- 如果请求 URL 是
https://你的域名/api/xxx,那是同源请求,CORS 错误说明 Nginx 没处理好转发,比如proxy_pass写错导致 502 之外的服务端错误。 - 如果请求 URL 是
https://localhost:8080/api/xxx或http://127.0.0.1:8080/api/xxx,那是前端代码里 baseURL 写死了绝对地址,需要改回/api重新打包。
这个判断一步到位,能帮你跳过好多无谓的配置文件修改。
7.5 常用命令速查表
附上一份平时部署排查用的命令清单,按需复制到宝塔终端执行:
| 目的 | 命令 |
|---|---|
| 查看 Java 进程 | ps -ef | grep java |
| 看后端日志(实时) | tail -f /www/wwwroot/你的项目名/server/app.log |
| 看 Nginx 错误日志 | tail -f /www/wwwroot/你的项目名/logs/error.log |
| 检查 Nginx 语法 | nginx -t |
| 重载 Nginx | nginx -s reload |
| 测试后端接口 | curl http://127.0.0.1:8080/api/health |
| 查看端口监听 | ss -tlnp |
| 查看系统内存 | free -h |
8. 一些部署细节上的个人体会
最后聊点实际操作中的碎片经验。
后端日志是排查故障的第一手资料,所以从第一天部署开始就要把日志配好。SpringBoot 的logging.file.name或者 logback 配置里指定文件路径,比把日志打到 stdout 再重定向更可控。我一般会把日志按日期切片,保留最近 30 天,避免磁盘被日志撑爆。
再说数据库编码。前端界面显示中文乱码,很多时候不是前端问题,而是数据库建库时默认字符集不是 utf8mb4。宝塔建库时尽量手动指定utf8mb4,导入.sql前确认文件本身的编码,这个锅经常甩来甩去,其实源头最早不要犯。
还有一个小细节:发布前修改前端代码后,记得清一下 CDN 缓存(如果挂了 CDN)。很多团队部署后反馈“线上没生效”,最后发现是 CDN 节点缓存了旧资源。如果暂时没上 CDN,就要靠 index.html 不缓存的新增配置,这个问题越早规划越好。
这套部署流程我前前后后走了很多遍,从最开始在服务器上各种踩坑、凌晨起来修 502,到现在基本一套流程走完半小时上线,中间沉淀下来的经验其实就那一句话:先想明白结构,再动手操作,最后按链路查问题。只要每一步都确认了再走下一步,前后端分离项目用宝塔面板部署这件事,确实不难。