Spring Boot + Vue 全栈应用云端部署实战:从零到一上云指南
1. 环境准备:从零搭建你的云端“地基”
很多朋友在本地把Spring Boot和Vue项目跑得飞起,一到要部署上云服务器就有点发怵,感觉像要进入一个陌生的世界。别担心,我刚开始也这样,踩过不少坑。今天我就把自己从零开始,把一个全栈项目成功部署上云的全过程,掰开揉碎了讲给你听。这个过程其实就像装修房子,服务器就是你的毛坯房,环境就是水电煤气,咱们一步步来,保证你能跟着做下来。
首先,你得有个“毛坯房”,也就是云服务器。我比较推荐新手从腾讯云或阿里云的轻量应用服务器开始,它们预装了一些基础系统,价格也实惠。选购时,操作系统建议选择CentOS 7.x、Ubuntu 20.04 LTS或者国产的OpenCloudOS,这些都是社区活跃、资料丰富的Linux发行版。我这次演示就用OpenCloudOS,它和CentOS兼容性很好。买好服务器后,记下它的公网IP地址,这是你未来访问网站的“门牌号”。然后,用SSH工具(比如Xshell、FinalShell,或者Mac/Linux自带的终端)连接上去,我们的“装修”工程就正式开始了。
连接上服务器后,第一件事不是急着装软件,而是更新系统并安装最基础的编译工具。这能确保后续安装过程顺畅。你可以依次执行下面这几条命令:
# 更新系统软件包列表 sudo yum update -y # 安装常用的编译工具和库,比如gcc、make等,这是后续安装很多软件的基础 sudo yum groupinstall "Development Tools" -y sudo yum install -y pcre-devel zlib-devel openssl-devel搞定基础工具后,我们就要安装项目的三大核心依赖:JDK、Node.js和数据库(这里以MySQL为例)。安装JDK是运行Spring Boot Jar包的前提。我习惯用yum直接安装OpenJDK,省去手动配置环境变量的麻烦。
# 搜索可用的JDK版本 sudo yum search java-11-openjdk # 安装JDK 11(Spring Boot 2.x/3.x的主流选择) sudo yum install -y java-11-openjdk-devel # 安装完成后验证 java -version接下来安装Node.js。Vue项目的打包依赖它。为了能方便地切换Node版本,我推荐使用Node Version Manager (nvm)来安装。
# 下载并安装nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash # 让终端重新加载配置,或者新开一个终端窗口 source ~/.bashrc # 使用nvm安装Node.js的长期支持版(LTS) nvm install --lts # 验证安装 node -v npm -v数据库方面,如果你项目里用到了MySQL,也需要在服务器上安装一个。直接用yum安装MariaDB(MySQL的一个流行分支)就行。
# 安装MariaDB服务器 sudo yum install -y mariadb-server # 启动数据库服务并设置开机自启 sudo systemctl start mariadb sudo systemctl enable mariadb # 运行安全初始化脚本,设置root密码等 sudo mysql_secure_installation执行最后一条命令时,会有一个交互式的向导,记得为root用户设置一个强密码,并移除测试数据库和匿名用户,这是生产环境的基本安全要求。完成这些,你的云端“地基”就算初步打好了。记住,每一步执行完都最好用-v或--version命令验证一下,确保安装成功,这是避免后续连环坑的好习惯。
1.1 安装与配置Nginx:你的全能“门卫”
Nginx在这里扮演着至关重要的角色:它既是Vue打包后静态文件(HTML、CSS、JS)的Web服务器,又是将前端API请求转发到后端Spring Boot应用的反向代理。用个形象的比喻,它就像公司的前台兼门卫,既负责展示公司形象(静态页面),又负责把访客(API请求)引导到正确的部门(后端服务)。
我更喜欢从源码编译安装Nginx,这样能获得最新的特性,并且可以自定义需要编译的模块。首先,我们去官网下载稳定版的源码包。
# 进入一个常用的源码存放目录,比如/usr/local/src cd /usr/local/src # 使用wget下载Nginx源码包(请替换为官网最新稳定版链接) sudo wget http://nginx.org/download/nginx-1.24.0.tar.gz # 解压源码包 sudo tar -zxvf nginx-1.24.0.tar.gz # 进入解压后的目录 cd nginx-1.24.0接下来是经典的“配置-编译-安装”三步曲。./configure命令会检查系统环境并生成编译所需的Makefile。我们可以通过参数开启一些常用模块,比如--with-http_ssl_module用于支持HTTPS。
# 执行配置脚本,这里指定安装路径为/usr/local/nginx sudo ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module # 编译(这个过程可能需要几分钟) sudo make # 安装 sudo make install安装完成后,Nginx的主程序会在/usr/local/nginx/sbin/目录下。为了方便使用,我们可以把它链接到系统的环境变量路径里。
# 创建软链接,这样在任何位置都能直接输入`nginx`命令了 sudo ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx现在,可以启动Nginx来测试一下了。
# 启动Nginx sudo nginx # 检查Nginx是否启动成功 ps aux | grep nginx如果看到有nginx: master process和nginx: worker process的进程在运行,说明启动成功。此时,打开你的浏览器,输入服务器的公网IP地址(比如http://你的服务器IP),如果能看到“Welcome to nginx!”的默认页面,恭喜你,“门卫”已经上岗了!如果看不到,可能是服务器的防火墙(如firewalld)没有开放80端口,你需要运行sudo firewall-cmd --permanent --add-service=http和sudo firewall-cmd --reload来放行。
1.2 安装与配置Redis:高性能“缓存管家”
如果你的Spring Boot项目用到了Redis做缓存或会话存储,那么在服务器上安装Redis也是必须的。Redis的安装同样简单,我们可以通过EPEL仓库来安装。
# 首先安装EPEL扩展仓库 sudo yum install -y epel-release # 更新仓库缓存后安装Redis sudo yum update -y sudo yum install -y redis # 启动Redis服务并设置开机自启 sudo systemctl start redis sudo systemctl enable redis # 检查Redis运行状态 sudo systemctl status redis安装完成后,默认的Redis配置已经可以满足基础开发需求。但为了安全,我强烈建议你做两件事:一是设置访问密码,二是限制只允许本地访问(因为我们的Spring Boot应用和Redis在同一台服务器上)。编辑Redis的配置文件:
sudo vi /etc/redis.conf在配置文件中找到这两行,并修改:
# 大约在61行,将绑定地址改为127.0.0.1,这样只允许本机连接 bind 127.0.0.1 # 大约在507行,找到`# requirepass foobared`,去掉注释并把`foobared`改成你自己的强密码 requirepass your_strong_password_here保存退出后,重启Redis服务使配置生效:
sudo systemctl restart redis最后,用Redis自带的命令行客户端测试一下连接和密码是否生效:
redis-cli # 连接后,执行认证命令 auth your_strong_password_here # 设置一个测试键值 set test "hello from redis" # 获取这个键值 get test如果能看到你设置的“hello from redis”,说明Redis已经正确安装并配置好了。这个“缓存管家”将为你的应用提速不少。
2. 前端Vue项目部署:让界面“安家落户”
环境准备好后,我们开始部署前端。这个过程的核心就两步:在本地把Vue项目“打包”成静态文件,然后把打包好的文件“搬家”到服务器上,并告诉Nginx去哪里找这些文件。
首先,回到你的本地开发机器,打开Vue项目。在打包之前,有一个关键配置需要检查:API请求的基地址。在开发时,我们通常用localhost:8080来连接本地的Spring Boot后端。但现在后端要部署到云服务器上,地址变了。你需要修改vue.config.js文件(如果没有就新建一个),配置生产环境的代理或直接设置axios的baseURL。
假设你的后端Spring Boot应用在服务器上将会运行在8080端口,服务器公网IP是123.123.123.123,那么配置可能像这样:
// vue.config.js module.exports = { devServer: { proxy: { '/api': { // 你前端请求接口的统一前缀 target: 'http://123.123.123.123:8080', // 云服务器后端地址 changeOrigin: true, pathRewrite: { '^/api': '' } } } }, // 或者,如果你在代码里直接使用axios,可以在创建实例时设置baseURL // 新建一个`src/api/request.js`文件 }更常见的做法是在项目中创建一个.env.production环境变量文件:
# .env.production VUE_APP_API_BASE_URL = http://123.123.123.123:8080然后在你的API请求模块(比如axios)中读取这个变量:
// src/utils/request.js import axios from 'axios'; const service = axios.create({ baseURL: process.env.VUE_APP_API_BASE_URL, // 读取环境变量 timeout: 5000 });配置好后,就可以开始打包了。在项目根目录下打开终端,运行:
npm run build或者如果你的package.json里定义了生产环境构建命令:
npm run build:prod这个命令会启动Webpack等打包工具,将你的Vue组件、路由、状态管理代码以及所有依赖,压缩、优化并打包成一个纯粹的静态资源文件夹,默认名称为dist。你会在项目根目录下看到这个新生成的dist文件夹,里面通常包含index.html、css、js等子文件夹。这就是你前端应用的全部“家当”。
接下来,我们需要把这些“家当”上传到云服务器。有很多方法,对于新手,我推荐使用scp命令(在Mac/Linux终端或Windows PowerShell/WSL中可用),它通过SSH协议安全地复制文件。
# 在本地机器终端执行,将dist文件夹整个上传到服务器的/usr/local/src/myapp/目录下 # 注意替换`your_username`为你的服务器登录用户名,`your_server_ip`为你的服务器公网IP scp -r ./dist your_username@your_server_ip:/usr/local/src/myapp/这个命令会把本地的dist文件夹递归地复制到服务器/usr/local/src/myapp/路径下。如果该路径不存在,scp会报错,所以最好先在服务器上创建好目录:
# 在服务器上执行 sudo mkdir -p /usr/local/src/myapp文件上传成功后,前端部署的物理部分就完成了。但此时直接访问服务器IP,看到的还是Nginx的欢迎页,而不是你的Vue应用。因为Nginx还不知道要去/usr/local/src/myapp/dist这个目录找文件。这就需要我们去修改Nginx的配置,给它指条明路。
2.1 配置Nginx托管前端静态资源
现在,我们要告诉Nginx这个“门卫”:“以后所有来访问网站根路径的请求,都去/usr/local/src/myapp/dist这个房间找文件接待”。这就需要编辑Nginx的配置文件。
# 使用vi或nano编辑器打开Nginx的主配置文件 sudo vi /usr/local/nginx/conf/nginx.conf我们需要重点关注http块里的server块。一个典型的、用于托管Vue单页应用并代理后端API的配置如下。我会在关键位置加上注释,你可以对照着修改或替换你配置文件中的server部分。
http { # ... 其他http模块全局配置 ... server { listen 80; # 监听80端口(HTTP默认端口) server_name your_server_ip; # 你的服务器公网IP,也可以填域名,如 www.yourdomain.com # 前端静态文件服务配置 location / { root /usr/local/src/myapp/dist; # 这里就是你刚才上传dist文件夹的绝对路径 index index.html index.htm; # 默认索引文件 try_files $uri $uri/ /index.html; # 非常重要!用于支持Vue Router的history模式,避免404 } # 后端API反向代理配置 # 假设你前端所有API请求都以 `/api` 开头 location /api/ { proxy_pass http://127.0.0.1:8080/; # 转发到本机运行的Spring Boot应用 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 30s; proxy_send_timeout 30s; proxy_read_timeout 30s; } # 可选的错误页面配置,将404错误也指向index.html,对SPA很友好 error_page 404 =200 /index.html; } }这里有几个关键点需要理解:
root指令:指定静态文件的根目录。当用户访问http://your_server_ip/about时,Nginx会去/usr/local/src/myapp/dist目录下寻找about文件或目录。对于Vue Router生成的路径,实际文件是不存在的,这就引出了下一条。try_files指令:这是支持Vue Routerhistory模式的核心。它的意思是:先尝试找$uri(请求的URI对应的真实文件),再尝试找$uri/(作为一个目录),如果都找不到,最后返回/index.html。这样,像/about这样的前端路由路径,虽然服务器上没有about这个文件,但最终会返回index.html,由前端的Vue Router来处理这个路由,完美解决了刷新页面404的问题。location /api/块:这是一个反向代理配置。所有以/api/开头的请求(比如前端发起的/api/user/login),都会被Nginx拦截,并转发到http://127.0.0.1:8080/(即本机8080端口运行的Spring Boot应用)。proxy_set_header系列指令是为了在转发时保留原始的请求头信息,方便后端获取真实客户端IP等。
修改完配置后,一定要检查配置文件语法是否正确,这是一个好习惯,能避免因为配置错误导致Nginx无法启动。
sudo nginx -t如果看到nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful的提示,说明配置语法正确。然后让Nginx重新加载配置,使改动生效:
sudo nginx -s reload现在,再次在浏览器中访问你的服务器公网IP(http://你的服务器IP)。如果一切顺利,你应该能看到你的Vue应用界面了!不过,此时点击需要调用后端接口的按钮,可能会失败或加载中,因为我们的Spring Boot后端还没部署呢。别急,我们马上就来解决它。
3. 后端Spring Boot项目部署:让服务“稳如泰山”
后端部署的核心思想是:将我们的Spring Boot应用打包成一个可执行的、包含所有依赖的“超级”JAR文件(即Fat Jar),然后把它放到服务器上,用Java命令运行起来。为了让这个服务在后台稳定运行,不受终端关闭的影响,我们还需要一些“守护”手段。
首先,回到本地开发环境,对Spring Boot项目进行打包前的最后配置检查。主要关注两点:数据库连接和文件存储路径。
数据库配置:打开
application.yml或application.properties文件,将数据库的url、username、password从本地的localhost和开发密码,修改为云服务器上MySQL的地址(通常是127.0.0.1或localhost)和你在安装MySQL时设置的强密码。# application-prod.yml (生产环境配置文件) spring: datasource: url: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: your_db_username password: your_strong_db_password driver-class-name: com.mysql.cj.jdbc.Driver文件路径:如果你的应用有文件上传功能,并且代码中写死了像
D:/upload/这样的Windows绝对路径,在Linux服务器上肯定会出错。你需要将其改为Linux的路径,比如/home/your_app/uploads/,并确保运行JAR包的用户对这个目录有读写权限。更好的做法是使用配置项,例如:file: upload-dir: /home/your_app/uploads/然后在代码中通过
@Value("${file.upload-dir}")注入使用。
配置检查无误后,就可以打包了。在项目根目录(包含pom.xml的目录)下,打开终端,运行Maven打包命令:
# 跳过测试,打包生产环境配置 mvn clean package -DskipTests -Pprod这里的-Pprod表示激活名为prod的Maven Profile,它通常会使用我们上面创建的application-prod.yml配置文件。打包成功后,你会在target目录下找到一个名字类似your-project-0.0.1-SNAPSHOT.jar的文件。这个就是我们可以独立运行的“超级”JAR包。
接下来,将这个JAR包上传到云服务器。同样使用scp命令:
scp target/your-project-0.0.1-SNAPSHOT.jar your_username@your_server_ip:/home/your_app/在服务器上,我们进入JAR包所在的目录,准备运行它。但直接运行java -jar命令有个问题:一旦你关闭SSH终端,这个Java进程也会随之终止。这显然不是我们想要的生产环境运行方式。我们需要让它在后台运行,并且即使终端关闭也能持续提供服务。有几种方法可以实现:
方法一:使用nohup(最简单直接)nohup命令可以让进程忽略挂断信号(SIGHUP),从而在终端关闭后继续运行。
cd /home/your_app # 使用nohup在后台运行jar包,并将标准输出和错误输出重定向到nohup.out文件 nohup java -jar your-project-0.0.1-SNAPSHOT.jar > nohup.out 2>&1 &命令解释:
nohup:保证进程不挂断。> nohup.out:将命令的标准输出重定向到nohup.out文件。2>&1:将标准错误输出也重定向到标准输出,即同样写入nohup.out。&:让命令在后台运行。 执行后,你可以用tail -f nohup.out来实时查看应用启动日志,就像在IDE里看控制台一样。
方法二:使用systemd服务(更专业、推荐)systemd是Linux系统标准的服务管理器。用它来管理Spring Boot应用,可以实现更精细的控制,如开机自启、自动重启、资源限制等。首先,我们创建一个服务单元文件。
sudo vi /etc/systemd/system/your-app.service将以下内容写入文件,注意替换Description、User、WorkingDirectory、ExecStart等参数为你自己的信息:
[Unit] Description=Your Spring Boot Application After=network.target syslog.target [Service] User=your_username # 建议用一个非root用户来运行,更安全 WorkingDirectory=/home/your_app ExecStart=/usr/bin/java -jar /home/your_app/your-project-0.0.1-SNAPSHOT.jar SuccessExitStatus=143 Restart=always # 应用异常退出时自动重启 RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target保存退出后,执行以下命令来启用并启动这个服务:
# 重新加载systemd配置,使其识别新的服务文件 sudo systemctl daemon-reload # 设置服务开机自启 sudo systemctl enable your-app.service # 立即启动服务 sudo systemctl start your-app.service # 查看服务状态和日志 sudo systemctl status your-app.service sudo journalctl -u your-app.service -f # 实时查看日志使用systemd管理后,你可以通过systemctl start/stop/restart/status your-app来方便地控制应用的生命周期,并且服务会在服务器重启后自动启动,非常省心。
3.1 验证与故障排查:打通前后端“任督二脉”
后端服务启动后,我们如何验证它是否正常工作,并且前端能成功访问到它呢?
第一步,检查后端服务本身:
- 查看日志:如果你用
nohup,看nohup.out文件;如果用systemd,用journalctl -u your-app.service -f。关注是否有启动成功的标志,比如“Started Application in X seconds”,或者是否有数据库连接失败等错误信息。 - 本地测试API:在服务器上,你可以用
curl命令直接测试后端API是否可达。
如果返回预期的JSON数据或状态码,说明后端服务在服务器本地运行正常。curl http://localhost:8080/api/health # 假设你有一个健康检查接口
第二步,验证Nginx反向代理: 后端服务在本地(127.0.0.1:8080)跑通了,现在要验证Nginx能否正确地将前端发来的/api/xxx请求转发过来。
- 在服务器上,用
curl测试经过Nginx转发的请求:
如果这个命令也能返回和上一步相同的结果,恭喜你!说明Nginx的反向代理配置成功了。Nginx成功地将对curl http://localhost/api/health # 注意,这里访问的是Nginx的80端口/api/health的请求,转发给了127.0.0.1:8080端口的Spring Boot应用。
第三步,从前端界面进行完整验证: 现在,回到你的浏览器,刷新之前打开的前端页面(http://你的服务器IP)。尝试进行一个需要调用后端API的操作,比如登录。
- 如果成功:页面正常跳转,数据正确显示,那么恭喜你,一个完整的Spring Boot + Vue全栈应用已经成功部署上云!
- 如果失败:打开浏览器的开发者工具(F12),切换到“网络”(Network)标签页,查看失败的API请求。重点关注:
- 状态码:404(Not Found)可能意味着Nginx的
location /api/路径没匹配上,或者后端接口路径不对。502(Bad Gateway)通常意味着Nginx无法连接到后端的Spring Boot服务(后端没启动或端口不对)。504(Gateway Timeout)可能是代理超时设置太短。 - 请求URL:检查请求是否确实发送到了
http://你的服务器IP/api/xxx,而不是本地地址。 - 控制台错误:查看“控制台”(Console)标签页是否有JavaScript错误。
- 状态码:404(Not Found)可能意味着Nginx的
常见“坑点”与解决方案:
- 端口被占用:Spring Boot默认端口是8080,确保没有其他程序占用。可以用
sudo netstat -tlnp | grep :8080查看。 - 防火墙阻拦:虽然我们后端只对本地(127.0.0.1)服务,但确保服务器的防火墙允许80端口(Nginx)入站。对于云服务器,还需要在云服务商的控制台(安全组)中放行80端口。
- 文件权限问题:运行Java应用的用户(如用
systemd指定的User)必须对JAR包所在目录、日志文件目录、上传文件目录等有读写权限。可以用chown和chmod命令修改。 - 数据库连接失败:确保服务器上的MySQL服务已启动,并且Spring Boot配置中的数据库用户名、密码、数据库名都正确。可以先用
mysql -u username -p命令在服务器上尝试连接数据库。 - 前端路由刷新404:这几乎100%是因为Nginx中缺少
try_files $uri $uri/ /index.html;这行配置。请务必在托管前端静态资源的location /块中加上它。
部署的过程就是不断遇到问题、解决问题的过程。每解决一个报错,你对整个系统的理解就会加深一层。当你在浏览器中看到自己开发的应用在公网上流畅运行时,那种成就感是非常棒的。记住,第一次部署可能会花些时间,但流程跑通后,以后再部署新版本就会非常快了,无非就是打包、上传、重启服务这几个步骤。
