
1. 项目概述与核心痛点最近在帮一个朋友的公司部署一套基于若依RuoYi框架开发的管理系统他们之前是开发团队在本地调试现在要正式上线。朋友听说宝塔面板BT Panel对运维新手很友好就让我用这个来搞。我一听就乐了宝塔部署常规的PHP或者静态网站确实方便但对付一个Spring Boot Vue的前后端分离Java项目尤其是像若依这种结构稍显复杂的那可真不是点几下鼠标就能完事的。整个过程简直就是一部“踩坑大全”从环境配置、项目打包到服务部署、反向代理设置几乎每一步都有“惊喜”。这篇文章我就把这次用宝塔面板部署RuoYi前后端分离项目的完整过程以及遇到的每一个坑和解决方案毫无保留地记录下来。如果你也正打算这么做或者已经在坑里了希望这篇实录能帮你省下大量折腾的时间。简单说RuoYi是一个基于Spring Boot、Shiro、MyBatis-Plus等技术的开源权限管理系统前端采用Vue/Element UI。我们要部署的是其前后端分离版本ruoyi-vue。目标是在一台安装了宝塔面板的Linux服务器以CentOS 7为例上让前端和后端服务都能稳定运行并通过域名访问。2. 环境准备与宝塔基础配置2.1 服务器与宝塔初始化首先你需要一台云服务器并安装好宝塔面板。这个过程宝塔官网有很详细的脚本一键安装即可这里不赘述。安装成功后通过http://你的服务器IP:8888登录宝塔面板。登录后第一件事不是急着建站而是去“软件商店”安装我们后续必需的运行环境Nginx 用于反向代理和托管前端静态文件。选择稳定版本安装即可。Java项目管理器 这是宝塔的一个插件对于管理Spring Boot的Jar包非常方便可以一键启动、停止、重启还能看日志。强烈建议安装比直接用systemd或nohup管理要直观得多。MySQL 用于存放若依系统的数据库。安装你需要的版本如5.7或8.0。Redis可选但推荐 若依默认使用Redis做缓存和会话管理安装它可以提升性能。注意 宝塔面板自带的“Tomcat”通常用于部署WAR包而RuoYi前后端分离版后端是打包成可执行Jar包的所以我们不需要安装Tomcat。Java项目管理器就是用来管理Jar包的。2.2 数据库与用户创建在宝塔面板的数据库菜单中创建一个新的MySQL数据库记下数据库名、用户名和密码。字符集建议选择utf8mb4排序规则utf8mb4_general_ci。然后你需要导入RuoYi的初始SQL文件。这个文件在RuoYi后端项目的sql目录下通常叫ry_2021xxxx.sql日期可能不同。你有两种方式导入方式一推荐使用宝塔面板 在宝塔的“数据库”页面找到你刚创建的库点击“导入”从本地上传SQL文件并执行。方式二使用命令行 如果文件已经在服务器上可以通过SSH连接到服务器使用mysql -u用户名 -p 数据库名 sql文件路径命令导入。确保导入成功数据库中应该出现了sys_、gen_等前缀的表。2.3 后端项目配置与打包这是第一个容易出错的环节。在本地开发环境你需要修改后端项目ruoyi-admin模块的关键配置文件。修改数据库连接 找到ruoyi-admin/src/main/resources/application-druid.yml。# 数据源配置 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ry-vue?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLtrueserverTimezoneGMT%2B8 username: root password: 你的密码将localhost改为你的服务器内网IP地址如果MySQL在同一个服务器上可以是127.0.0.1或localhostry-vue改为你创建的数据库名用户名和密码也要对应修改。这里不要用外网IP除非数据库在另一台服务器。修改Redis连接如果安装了 找到application.yml中的Redis配置部分。# redis 配置 redis: # 地址 host: 127.0.0.1 # 端口默认为6379 port: 6379 # 数据库索引 database: 0 # 密码 password: # 连接超时时间 timeout: 10s通常保持127.0.0.1和6379即可如果你设置了Redis密码需要在这里填写。修改后端服务端口可选 在application.yml中可以指定后端服务启动的端口默认是8080。server: port: 8080如果8080端口被占用可以改成其他端口比如8088。执行打包 在项目根目录有pom.xml的目录下执行Maven打包命令。这里有个大坑。错误做法 直接mvn clean package。这样打出来的Jar包在宝塔的Java项目管理器中运行访问前端时可能会遇到“Invalid CORS request”跨域错误尽管你在代码里配置了跨域。这是因为打包时可能没有包含完整的依赖或配置。正确做法 使用Spring Boot的Repackage目标或者直接打包ruoyi-admin模块。# 在项目根目录下推荐使用这个命令 mvn clean package -DskipTests # 或者进入 ruoyi-admin 目录再打包 cd ruoyi-admin mvn clean package -DskipTests打包成功后你会在ruoyi-admin/target/目录下找到一个名字类似ruoyi-admin.jar的文件。这个就是我们需要部署的后端程序。实操心得 在本地打包前务必确保所有配置文件的修改是针对生产环境的尤其是数据库地址。一个常见的错误是本地配置文件里数据库连的是localhost打包后直接上传服务器导致后端服务启动后连不上数据库。建议在IDEA里使用Maven的prodprofile打包或者在打包前仔细检查application-druid.yml等文件。3. 前端项目构建与部署3.1 前端项目配置与构建前端项目通常是ruoyi-ui目录的配置相对简单主要是设置后端API的代理地址。修改API代理配置 找到ruoyi-ui/.env.production文件生产环境配置。# 后端API地址修改为你的后端服务访问地址 VUE_APP_BASE_API /prod-api这里VUE_APP_BASE_API是前端请求的基路径。更重要的是我们需要修改Vue CLI的代理配置。找到ruoyi-ui/vue.config.js文件修改devServer.proxy配置devServer: { port: port, open: true, overlay: { warnings: false, errors: true }, proxy: { // 开发环境代理配置生产环境由Nginx处理 // 如果你打算在宝塔用Nginx反向代理这里的生产环境构建不需要改但理解它很重要 [process.env.VUE_APP_BASE_API]: { target: http://localhost:8080, // 这里原来是本地后端地址 changeOrigin: true, pathRewrite: { [^ process.env.VUE_APP_BASE_API]: } } } },注意vue.config.js里的proxy只在开发环境npm run dev生效。当我们执行npm run build:prod进行生产环境构建时生成的是纯静态文件HTML, JS, CSS代理配置不会被打包进去。生产环境的请求转发需要依靠部署后的Web服务器如Nginx来实现。所以对于生产构建我们主要关心.env.production中的VUE_APP_BASE_API它会被编译进静态资源用于前端JS代码拼接请求URL。执行生产环境构建 在ruoyi-ui目录下确保已安装依赖npm install然后运行构建命令。npm run build:prod这个过程可能会因为网络问题下载依赖包失败可以尝试设置淘宝镜像npm config set registry https://registry.npmmirror.com。构建成功后会在项目根目录下生成一个dist文件夹里面就是我们要部署的前端静态文件。3.2 宝塔面板部署前端创建网站 在宝塔面板的“网站”菜单点击“添加站点”。域名 填写你要访问的域名如admin.yourdomain.com或者暂时用服务器IP地址。根目录 选择一个目录比如/www/wwwroot/admin。这个目录将存放我们前端dist文件夹里的内容。FTP和数据库 根据需求创建这里可以都不选。PHP版本 选择“纯静态”即可因为我们部署的是Vue构建的静态资源。上传前端文件 通过宝塔的文件管理器进入你刚创建的网站根目录如/www/wwwroot/admin。删除这个目录下默认生成的所有文件如index.html,404.html等。然后将本地构建好的dist文件夹里的所有内容注意是dist文件夹内的文件不是dist文件夹本身上传到这个网站根目录。配置Nginx反向代理关键步骤 这是前后端分离部署的核心也是最容易出错的地方。点击你刚创建网站的“设置”按钮进入“配置文件”选项卡。 我们需要修改Nginx配置实现两个功能一是正确服务前端静态文件二是将前端对后端API的请求代理到真正的后端Java服务上。以下是一个关键的配置示例你需要添加到server { ... }块中server { listen 80; server_name admin.yourdomain.com; # 你的域名 root /www/wwwroot/admin; # 前端文件根目录 # 前端静态文件服务 location / { try_files $uri $uri/ /index.html; index index.html index.htm; } # 代理后端API请求 - 这是核心配置 location /prod-api/ { # 这个路径需要与前端 VUE_APP_BASE_API 对应 proxy_pass http://127.0.0.1:8080/; # 代理到后端Java服务地址和端口 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 以下配置对于文件上传等功能很重要 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; client_max_body_size 100m; # 设置允许上传的文件大小 } # 可选静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }配置解析location /: 处理所有根路径请求。try_files $uri $uri/ /index.html;这条指令是Vue、React等单页面应用SPA的标配。它的作用是当Nginx找不到请求的文件时比如你刷新了/system/user这个前端路由页面会返回index.html由前端的Vue Router来处理路由从而避免404错误。location /prod-api/: 这是最重要的部分。当前端发起任何以/prod-api/开头的请求例如/prod-api/loginNginx会拦截这个请求并将其转发代理到http://127.0.0.1:8080/即我们后端Spring Boot服务。proxy_pass后面的/很重要它意味着将/prod-api这个前缀去掉后再转发给后端。所以前端请求/prod-api/login实际到达后端的是/login。proxy_set_header系列指令 用于将客户端的真实IP等信息传递给后端服务否则后端日志里看到的客户端IP都是127.0.0.1。client_max_body_size: 如果你的系统有文件上传功能务必调大这个值如100m否则上传大文件会报413 Request Entity Too Large错误。修改完配置后保存并重载Nginx服务。4. 后端服务部署与启动4.1 使用宝塔Java项目管理器这是比手动命令更优雅的管理方式。上传Jar包 在宝塔文件管理器中创建一个专门存放Java项目的目录例如/www/java。将之前打包好的ruoyi-admin.jar上传到这个目录。添加Java项目 打开“软件商店”里已安装的“Java项目管理器”点击“添加项目”。项目路径 选择你上传的Jar包如/www/java/ruoyi-admin.jar。项目名称 自定义如ruoyi-backend。项目端口 填写你在application.yml中配置的端口默认8080。确保这个端口在服务器防火墙宝塔的安全菜单和云服务商的安全组中是放行的。运行参数 可以留空或者根据需要添加JVM参数例如设置内存-Xmx512m -Xms256m。JDK版本 选择你项目所需的版本若依一般需要JDK8或以上。启动项目 点击“添加”后在项目列表中点击“启动”。如果一切配置正确项目状态会变为“运行中”。你可以点击“日志”查看启动过程确认没有报错特别是数据库连接和Redis连接是否成功。4.2 验证后端服务启动后我们可以先验证后端服务本身是否正常暂时不通过前端Nginx代理。在宝塔的“安全”菜单放行你后端服务的端口如8080。在浏览器直接访问http://你的服务器IP:8080。如果看到RuoYi的后端接口文档页面Swagger UI或者一个简单的欢迎页说明后端服务已经独立启动成功。5. 常见问题与排查实录部署过程中我遇到了几乎所有典型问题这里汇总一下5.1 前端访问空白页或404症状 访问域名页面空白浏览器控制台报错加载不到JS/CSS文件或者刷新非首页路由出现404。原因与解决Nginx根目录错误 确认网站根目录设置是否正确并且dist文件夹内的文件是否直接放在了根目录下而不是多了一层dist目录。缺少try_files $uri $uri/ /index.html; 这是SPA应用最常见的问题。必须确保Nginx配置中location /块里有这条指令。静态资源路径错误 如果控制台报错找不到/css/app.xxxx.css等文件可能是前端构建时公共路径publicPath问题。检查vue.config.js中的publicPath配置生产环境通常应为./或/。5.2 前端能打开但登录接口报404或网络错误症状 打开登录页正常点击登录后浏览器F12网络面板显示对/prod-api/login的请求失败404, 502等。原因与解决Nginx代理配置错误 这是最可能的原因。检查Nginx配置中的location /prod-api/块。proxy_pass的地址和端口是否正确是否写成了http://127.0.0.1:8080末尾有斜杠和没有斜杠含义不同按上文配置即可。location的路径/prod-api/是否与前端的VUE_APP_BASE_API变量值完全一致包括斜杠后端服务未启动 去宝塔Java项目管理器查看服务状态是否为“运行中”查看日志是否有启动错误。端口冲突或防火墙 确认后端服务端口如8080是否被其他程序占用。在服务器上用netstat -tlnp | grep 8080查看。同时确认宝塔防火墙和云服务器安全组都放行了该端口。5.3 登录成功但跳转回登录页或提示“无效的CORS请求”症状 输入账号密码点击登录页面闪一下似乎成功了但又跳回登录页或者浏览器控制台出现CORS跨域错误。原因与解决会话Session或令牌Token问题 前后端分离项目通常使用Token如JWT或Session保持登录状态。确保前端在请求成功后正确存储了后端返回的Token通常是在localStorage或cookie中并在后续请求的Header如Authorization中携带。Nginx代理丢失Cookie/Header 在Nginx的location /prod-api/配置中添加以下指令确保Cookie和认证头信息被正确传递proxy_cookie_path / /; proxy_set_header Cookie $http_cookie; # 如果使用Token通常不需要上面两行但确保其他头信息传递 proxy_set_header Authorization $http_authorization; proxy_pass_header Authorization;后端CORS配置在打包后未生效 这是一个深坑。在开发环境Spring Boot的CORS配置可能通过CrossOrigin注解或WebMvcConfigurer配置得很好。但在生产环境当通过Nginx代理时请求来源Origin变成了Nginx服务器本身如127.0.0.1这可能绕过或与后端的CORS配置产生冲突。最可靠的解决方案是在生产环境主要依靠Nginx来管理CORS或者确保后端配置允许Nginx代理的地址。可以在Spring Boot配置中设置更宽松的CORSConfiguration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) // 使用allowedOriginPatterns替代allowedOrigins以支持模式匹配 .allowCredentials(true) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .maxAge(3600); } }但更安全的做法是在Nginx层面添加CORS头并严格指定允许的源$http_origin。5.4 文件上传失败413 Request Entity Too Large症状 上传稍大的文件时Nginx直接返回413错误。解决 在Nginx配置的server块或location /prod-api/块中添加或修改client_max_body_size指令例如client_max_body_size 100m;。修改后务必重载Nginx。5.5 后端服务启动失败日志报数据库连接错误症状 Java项目管理器日志显示“Access denied for user rootlocalhost”或“Unknown database ry-vue”。解决仔细核对application-druid.yml中的数据库URL、用户名、密码。密码中如果包含特殊字符可能需要用URL编码。确认MySQL用户是否有从localhost或127.0.0.1连接的权限。可以在宝塔的phpMyAdmin或命令行中执行GRANT ALL PRIVILEGES ON 你的数据库名.* TO 你的用户名localhost IDENTIFIED BY 你的密码 WITH GRANT OPTION; FLUSH PRIVILEGES;确认MySQL服务是否正常运行。5.6 关于宝塔运行后 PM2 的运行者为 root现象 如果你在宝塔中使用了PM2管理器来管理Node.js项目虽然RuoYi-Vue前端是静态资源不需要可能会发现PM2进程的运行用户是root。分析与建议 这是因为宝塔面板本身是以root权限运行的它启动的PM2服务自然也继承了root身份。从安全角度讲这不是最佳实践因为以root运行应用会增加风险。处理 对于生产环境更安全的做法是创建一个专用用户如www来运行应用。但对于宝塔这种集成面板修改起来比较麻烦可能需要手动修改PM2的启动脚本或使用su命令切换用户。如果安全要求不是极高且服务器只有你一个人管理许多用户会暂时接受这个现状。但对于重要的业务系统建议研究如何以非root用户运行宝塔相关服务或者考虑更传统的部署方式。整个部署流程走下来最大的体会就是工具宝塔确实简化了服务器环境的管理但对于一个具体的、架构稍复杂的应用理解其运行原理前后端如何通信、Nginx如何代理、静态资源如何服务远比会点按钮更重要。每踩一个坑都是对这套技术栈理解加深的过程。希望这份详细的踩坑记录能让你在部署RuoYi或者类似Spring BootVue项目时少走些弯路。如果遇到其他问题多看日志Nginx错误日志、Java项目运行日志日志里的信息通常能直接指引你找到问题的根源。