尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Spring Boot+Vue项目部署实战:从环境搭建到内网穿透全流程

Spring Boot+Vue项目部署实战:从环境搭建到内网穿透全流程 1. 从本地到公网一个全栈项目的部署全景图最近在帮一个朋友的公司部署他们内部的管理系统技术栈是经典的 Spring Boot 后端 Vue 前端。项目在本地开发环境跑得飞起但一到部署环节从服务器选型、环境配置、前后端打包再到最后让外网用户能访问整个链路下来问题层出不穷。我发现很多开发者在“最后一公里”的部署上经验是零散的网上教程要么只讲后端要么只讲前端要么只讲服务器基础命令真正把前后端项目从代码变成公网可访问服务的完整流程尤其是涉及内网穿透这种特殊场景的讲透的很少。今天我就以这个实战项目为蓝本拆解 Spring Boot Vue 项目的完整部署流程。我们的目标很明确将你的本地开发项目变成一个稳定运行在服务器上、并能通过互联网访问的正式服务。这个过程我会涵盖从最基础的服务器环境准备到前后端应用的构建与配置再到通过 Nginx 进行整合与代理最后针对没有公网 IP 的服务器比如公司内网、家庭宽带详细讲解如何利用内网穿透技术实现公网访问。每一个步骤我都会解释“为什么这么做”并附上我踩过的坑和总结的最佳实践确保你不仅能部署成功还能理解背后的原理。2. 部署基石服务器环境与核心工具链搭建在写第一行部署命令之前我们必须先准备好战场。很多人部署失败问题往往就出在环境上。这里我们不假设你有一台带公网 IP 的云服务器而是从更通用的角度出发你有一台可以安装 Linux 系统的机器物理机、虚拟机、云服务器均可我们将把它打造成一个合格的应用服务器。2.1 操作系统选择与基础配置对于 Java 和 Node.js 应用CentOS 7/8 或 Ubuntu 20.04/22.04 LTS是经过大量生产环境验证的稳定选择。我个人近期更倾向于 Ubuntu因为其软件源更新更及时社区支持活跃。以 Ubuntu 22.04 为例第一件事是更新系统并安装必要的工具。# 更新软件包列表和已安装的包 sudo apt update sudo apt upgrade -y # 安装后续部署可能用到的基础工具 sudo apt install -y curl wget vim git net-tools htop接下来是一个关键但常被忽略的步骤配置 Swap 交换分区。尤其是对于内存较小的服务器如 1G、2G在编译前端项目或运行多个 Java 应用时极易因内存不足而崩溃。添加 Swap 相当于给内存加了“应急缓冲区”。# 检查当前Swap情况 sudo swapon --show # 如果没有任何输出说明没有启用Swap我们来创建一个4G的Swap文件 sudo fallocate -l 4G /swapfile # 设置正确的权限 sudo chmod 600 /swapfile # 将其格式化为Swap空间 sudo mkswap /swapfile # 启用Swap文件 sudo swapon /swapfile # 使其永久生效写入 /etc/fstab echo /swapfile none swap sw 0 0 | sudo tee -a /etc/fstab # 验证Swap已生效 free -h这个操作在我部署内存仅为 1G 的测试服务器时救过好几次命特别是npm run build的时候。2.2 Java 运行环境JDK 的选型与安装Spring Boot 项目离不开 JDK。这里有个重要选择用 OpenJDK 还是 Oracle JDK对于绝大多数生产环境OpenJDK是首选因为它完全开源免费且功能与 Oracle JDK 几乎一致。我们将安装 OpenJDK 17Spring Boot 2.7 和 3.0 的推荐版本。# 安装 OpenJDK 17 sudo apt install -y openjdk-17-jdk # 验证安装 java -version # 输出应类似openjdk version 17.0.10 2024-01-16安装后建议设置JAVA_HOME环境变量虽然 Spring Boot 打包的 jar 通常不依赖它但一些监控工具或脚本可能会用到。# 查找 JDK 安装路径 sudo update-alternatives --config java # 记下路径例如 /usr/lib/jvm/java-17-openjdk-amd64/bin/java # 那么 JAVA_HOME 就是 /usr/lib/jvm/java-17-openjdk-amd64 # 编辑环境变量文件 sudo vim /etc/environment # 在文件末尾添加请替换为你的实际路径 JAVA_HOME/usr/lib/jvm/java-17-openjdk-amd64 # 保存退出后使配置生效 source /etc/environment echo $JAVA_HOME注意有些教程会教你安装 Oracle JDK过程复杂且涉及许可协议。对于生产部署除非有明确的、必须使用 Oracle 专有特性的需求否则坚持使用 OpenJDK 能避免很多潜在的法律和技术麻烦。2.3 Node.js 与 npm前端构建的引擎Vue 项目的构建依赖 Node.js 和 npm或 yarn、pnpm。这里切忌使用系统自带的古老版本。我们通过 NodeSource 仓库安装最新的长期支持LTS版本。# 下载并执行 NodeSource 安装脚本以 Node.js 20.x 为例 curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - # 安装 Node.js它会同时安装 npm sudo apt install -y nodejs # 验证安装 node --version # 应输出 v20.x.x npm --version # 应输出 10.x.x安装完成后一个提升效率的技巧是配置 npm 的全局安装路径和镜像源。默认全局安装需要 sudo 权限这有安全风险。我们将其配置到用户目录下。# 创建全局安装目录 mkdir -p ~/.npm-global # 配置 npm 使用此目录 npm config set prefix ~/.npm-global # 将目录添加到 PATH 环境变量 echo export PATH~/.npm-global/bin:$PATH ~/.bashrc source ~/.bashrc # 可选但推荐配置淘宝 NPM 镜像以加速国内下载 npm config set registry https://registry.npmmirror.com/2.4 反向代理与静态服务Nginx 安装与初步配置Nginx 在我们的架构中扮演两个核心角色1. 作为反向代理将前端请求转发到后端 Spring Boot 应用2. 作为静态文件服务器直接提供 Vue 打包后的 HTML、JS、CSS 文件。安装 Nginx 很简单sudo apt install -y nginx # 启动 Nginx 并设置开机自启 sudo systemctl start nginx sudo systemctl enable nginx安装后在浏览器访问你的服务器 IP如果服务器有公网IP应该能看到 Nginx 的欢迎页面。这证明 Nginx 已成功运行。它的核心配置文件位于/etc/nginx/nginx.conf而站点配置文件通常放在/etc/nginx/sites-available/并通过软链接到/etc/nginx/sites-enabled/。我们暂时不动它等前后端应用准备好后再进行详细配置。至此我们的服务器已经具备了运行 Java 和 Node.js 应用并通过 Web 服务器对外提供服务的全部基础能力。环境一致性是部署成功的首要保障请务必确保每一步都执行无误。3. 后端部署Spring Boot 应用的生产级发布后端部署的核心是将我们开发的 Spring Boot 项目打包成一个可独立运行的 JAR 文件并在服务器上以服务的形式稳定运行。这里面的门道远不止一个java -jar命令那么简单。3.1 项目构建从源码到可部署的 JAR首先我们需要在本地或 CI/CD 环境中将项目打包。使用 Maven 或 Gradle。关键点在于构建配置。以 Maven 为例确保你的pom.xml中引入了spring-boot-maven-plugin。build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId version${spring-boot.version}/version !-- 与你的Spring Boot版本一致 -- executions execution goals goalrepackage/goal !-- 这个goal会生成可执行jar -- /goals /execution /executions configuration !-- 指定主类通常插件能自动识别显式声明更稳妥 -- mainClasscom.yourcompany.yourapp.Application/mainClass /configuration /plugin /plugins /build在项目根目录执行打包命令# 跳过测试加快打包速度 mvn clean package -DskipTests打包成功后你会在target目录下找到两个 JAR 文件一个是your-app-0.0.1-SNAPSHOT.jar另一个是your-app-0.0.1-SNAPSHOT.jar.original。前者是 Spring Boot 插件重新打包过的、包含所有依赖的可执行 JAR后者是原始的模块 JAR。我们需要的是前者。实操心得在打包前务必检查application.properties或application.yml中的配置特别是数据库连接、Redis地址等。生产环境的配置应该与开发环境分离。一种常见的做法是使用application-prod.yml文件并在打包时通过-Dspring.profiles.activeprod参数指定激活。或者更安全的方式是将敏感配置如密码放在服务器环境变量或配置中心而不是代码仓库里。3.2 服务器部署与服务化运行将打包好的 JAR 文件上传到服务器。可以使用scp命令或 SFTP 工具。假设我们上传到服务器的/opt/app/backend目录。# 在服务器上创建目录 sudo mkdir -p /opt/app/backend # 假设JAR文件在本地当前目录使用scp上传从本地机器执行 scp target/your-app-0.0.1-SNAPSHOT.jar useryour-server-ip:/opt/app/backend/接下来是最关键的一步如何运行这个 JAR直接nohup java -jar ... 是最简单的方式但不利于管理查看日志、重启、开机自启等。生产环境强烈推荐使用 Systemd 来管理 Spring Boot 应用它能提供完善的服务生命周期管理。创建一个 Systemd 服务单元文件sudo vim /etc/systemd/system/springboot-app.service写入以下内容请根据你的实际情况修改[Unit] DescriptionSpring Boot Backend Application Aftersyslog.target network.target [Service] Typesimple # 启动服务的用户建议使用非root用户如appuser Userappuser Groupappuser # 指定工作目录日志、临时文件会在这里生成 WorkingDirectory/opt/app/backend # 启动命令。这里示例了设置激活的生产环境配置文件、JVM内存参数 ExecStart/usr/bin/java -Xms512m -Xmx1024m -jar -Dspring.profiles.activeprod /opt/app/backend/your-app-0.0.1-SNAPSHOT.jar # 当服务失败时自动重启 Restarton-failure # 重启间隔 RestartSec10 [Install] WantedBymulti-user.target这里有几个细节用户与权限创建一个专用用户来运行服务sudo adduser --system --no-create-home appuser这比用 root 用户安全得多。JVM 参数-Xms和-Xmx设置了堆内存的初始大小和最大值。根据你的服务器内存和应用需求调整。设置得太小会导致频繁GC甚至OOM太大则可能挤占系统其他进程资源。配置文件-Dspring.profiles.activeprod激活名为prod的配置文件。你需要在服务器上准备application-prod.yml文件并放在 JAR 文件同级目录或 classpath 下。保存退出后启用并启动服务# 重新加载systemd配置 sudo systemctl daemon-reload # 启用开机自启 sudo systemctl enable springboot-app.service # 启动服务 sudo systemctl start springboot-app.service # 查看服务状态和日志 sudo systemctl status springboot-app.service sudo journalctl -u springboot-app.service -f # 实时查看日志如果状态显示active (running)并且日志中没有报错说明后端应用已经成功在后台运行。默认情况下Spring Boot 应用会在8080端口启动。你可以用curl localhost:8080/api/health假设你有健康检查接口来验证。3.3 生产环境配置要点与故障排查部署后常会遇到几个问题端口冲突确保8080端口没有被其他程序占用 (sudo netstat -tlnp | grep :8080)。数据库连接失败检查application-prod.yml中的数据库地址、用户名、密码是否正确以及服务器防火墙是否允许访问数据库端口。文件权限问题如果应用需要写日志或上传文件确保运行用户如appuser对相关目录有写权限。内存不足通过journalctl查看日志如果看到OutOfMemoryError需要调整 Systemd 服务文件中的-Xmx参数并确保服务器有足够的物理内存和 Swap 空间。一个高级技巧是配置JVM 垃圾回收日志便于后续性能分析和问题排查。在ExecStart行添加以下参数-XX:UseG1GC -XX:PrintGCDetails -XX:PrintGCDateStamps -Xloggc:/opt/app/backend/logs/gc.log同时记得创建logs目录并赋予appuser写权限。4. 前端部署Vue 项目的构建与静态化托管前端 Vue 项目在部署时需要先进行构建Build生成纯粹的 HTML、CSS、JavaScript 文件然后将这些静态文件交给 Web 服务器如 Nginx托管。这个过程的核心在于构建配置和与后端的对接。4.1 构建优化与关键配置进入 Vue 项目根目录首先安装依赖如果node_modules未上传或需要更新npm install --registryhttps://registry.npmmirror.com # 使用国内镜像加速接下来是构建。直接运行npm run build会使用 Vue CLI 默认的配置。但对于生产环境我们通常需要关注以下几点这些配置通常在vue.config.js文件中公共路径publicPath这决定了打包后的静态资源js, css, 图片在部署时的基础 URL。如果你打算将前端应用放在域名的根路径下如https://yourdomain.com可以设为/。如果打算放在子路径下如https://yourdomain.com/admin则必须设为/admin/。这个配置必须与 Nginx 的配置严格对应否则会导致资源加载失败。输出目录outputDir构建产物的文件夹默认为dist。环境变量通过.env.production文件注入生产环境变量例如后端 API 的基础地址。一个典型的vue.config.js生产配置可能如下const { defineConfig } require(vue/cli-service) module.exports defineConfig({ transpileDependencies: true, // 生产环境公共路径假设我们部署在根目录 publicPath: process.env.NODE_ENV production ? / : /, // 输出目录 outputDir: dist, // 静态资源目录js, css, img, fonts assetsDir: static, // 是否生成生产环境的 source map关闭以加速构建和保护源码 productionSourceMap: false, // 开发服务器代理配置仅用于开发部署时不生效 devServer: { proxy: { /api: { target: http://localhost:8080, // 你的后端地址 changeOrigin: true } } } })而.env.production文件则可能包含NODE_ENVproduction VUE_APP_API_BASE_URL/api # 这里很重要前端请求会发到 /api这里有一个关键点在开发时我们利用devServer.proxy将/api请求代理到后端解决了跨域问题。但在生产环境这个配置是无效的。生产环境的跨域问题如果前端和后端不在同一个域名/端口下需要通过Nginx 反向代理或者后端配置 CORS来解决。我们通常采用 Nginx 方案这样更高效。配置好后执行构建命令npm run build构建成功后会在项目根目录生成一个dist文件夹里面就是我们需要部署的全部静态文件。4.2 静态文件上传与 Nginx 托管将dist文件夹内的全部内容上传到服务器。假设我们打算将其放在/opt/app/frontend目录下。# 在服务器上创建目录 sudo mkdir -p /opt/app/frontend # 使用scp或rsync上传整个dist目录内容从本地机器执行 scp -r dist/* useryour-server-ip:/opt/app/frontend/现在我们需要配置 Nginx 来托管这些静态文件并处理对后端 API 的转发。编辑 Nginx 的站点配置文件sudo vim /etc/nginx/sites-available/your-app写入以下配置这是最核心的部分请仔细理解每一行server { listen 80; server_name your-domain.com; # 你的域名如果没有域名就用服务器IP这里先写IP或localhost # 前端静态文件根目录 root /opt/app/frontend; index index.html; # 处理前端路由如Vue Router的history模式 # 核心当请求的不是一个真实存在的文件或目录时都返回index.html由前端路由处理 location / { try_files $uri $uri/ /index.html; } # 反向代理到后端Spring Boot应用 # 所有以 /api 开头的请求都转发到本机的8080端口 location /api/ { # 注意结尾的斜杠它会影响代理时URL的重写 proxy_pass http://localhost: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; proxy_set_header X-Forwarded-Proto $scheme; # 如果后端应用需要较长时间处理可调整超时设置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } # 可选静态资源缓存优化提升性能 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }配置解析location /try_files指令是支持 Vue Routerhistory模式的关键。它尝试按顺序寻找文件先找请求的URI本身再找URI对应的目录如果都找不到最后返回/index.html。这样像/user/profile这样的前端路由就不会被 Nginx 当作文件请求而返回 404。location /api/将前端请求中所有/api路径的请求如/api/user/login透明地转发到运行在localhost:8080的后端应用。proxy_set_header系列指令是为了将客户端的真实IP等信息传递给后端否则后端日志里看到的客户端IP都是127.0.0.1。静态资源缓存对图片、CSS、JS 等设置长期缓存利用浏览器缓存大幅提升页面加载速度。启用这个站点配置并测试# 创建软链接到sites-enabled目录 sudo ln -s /etc/nginx/sites-available/your-app /etc/nginx/sites-enabled/ # 测试Nginx配置语法是否正确 sudo nginx -t # 如果显示“syntax is ok”和“test is successful”则重载Nginx配置 sudo systemctl reload nginx现在访问你的服务器 IP或配置的域名应该能看到 Vue 前端页面。尝试点击一个需要调用后端 API 的功能在浏览器开发者工具的“网络”标签页中你应该能看到请求发往/api/xxx并且成功返回数据。这证明前后端已经通过 Nginx 成功连接。踩坑记录最常见的错误是location /api/的proxy_pass指令结尾的斜杠。proxy_pass http://localhost:8080/;有斜杠会将/api/user转发为http://localhost:8080/user。而proxy_pass http://localhost:8080;无斜杠则会转发为http://localhost:8080/api/user。你必须根据你的后端应用是否期望/api前缀来决定如何配置。通常如果后端 Controller 的根路径就是/api那么用不带斜杠的版本如果后端根路径是/那么用带斜杠的版本去掉/api前缀。务必与后端开发者确认。5. 内网穿透让本地服务拥有公网地址前面我们假设服务器有公网 IP。但现实是很多开发环境、测试环境甚至是一些小公司的生产服务器都位于公司或家庭路由器之后没有独立的公网 IP。外部网络无法直接访问。这时就需要内网穿透NAT Traversal技术。其原理是在公网云服务器上运行一个服务端在你的内网服务器上运行一个客户端。客户端与公网服务端建立一条加密隧道将内网服务的端口“映射”到公网服务器的某个端口上。外部用户访问公网服务器的这个端口流量就会通过隧道转发到你的内网服务。市面上有许多内网穿透工具如 frp、ngrok、花生壳等。这里我选择frp (Fast Reverse Proxy)进行讲解因为它开源、免费、配置灵活、性能好。5.1 公网服务器端frps配置你需要一台具有公网 IP 的云服务器如腾讯云、阿里云、AWS 的轻量应用服务器作为中转。在这台服务器上部署 frp 的服务端frps。下载 frp访问 frp 的 GitHub Release 页面选择适合你服务器操作系统通常是 linux_amd64的版本。wget https://github.com/fatedier/frp/releases/download/v0.54.0/frp_0.54.0_linux_amd64.tar.gz tar -zxvf frp_0.54.0_linux_amd64.tar.gz cd frp_0.54.0_linux_amd64你会看到frps服务端程序和frps.ini服务端配置文件。配置 frps.inisudo vim frps.ini写入以下基础配置[common] bind_port 7000 # frp 服务端监听端口用于与客户端通信 # 认证令牌增强安全性客户端需要配置相同的token才能连接 token your_secure_token_here # 仪表板端口用于查看连接状态可选但推荐 dashboard_port 7500 dashboard_user admin dashboard_pwd admin_pwd_here # 日志记录 log_file ./frps.log log_level info log_max_days 3token和dashboard_pwd务必修改为强密码。运行 frps最简单的方式是使用nohup在后台运行但更推荐使用 Systemd 管理类似我们管理 Spring Boot 应用。# 创建systemd服务文件 sudo vim /etc/systemd/system/frps.service[Unit] DescriptionFrp Server Service Afternetwork.target [Service] Typesimple Usernobody Restarton-failure RestartSec5s # 假设frp解压到了 /opt/frp ExecStart/opt/frp/frps -c /opt/frp/frps.ini [Install] WantedBymulti-user.targetsudo systemctl daemon-reload sudo systemctl enable frps sudo systemctl start frps sudo systemctl status frps防火墙开放端口必须在云服务器的安全组/防火墙中开放7000端口frp 通信和7500端口仪表板如果启用。# 如果使用ufwUbuntu sudo ufw allow 7000/tcp sudo ufw allow 7500/tcp sudo ufw reload现在你可以通过http://你的公网服务器IP:7500访问 frp 仪表板输入用户名密码查看状态。5.2 内网服务器端frpc配置在你的内网服务器即运行 Spring Boot 和 Vue 的那台机器上部署 frp 的客户端frpc。下载并解压 frp同样步骤选择对应架构。配置 frpc.inivim frpc.ini写入以下配置这是将我们本地的 Web 服务通过 Nginx 在 80 端口监听暴露到公网的关键[common] server_addr 你的公网服务器IP server_port 7000 token your_secure_token_here # 必须与frps.ini中的token一致 [web] # 自定义一个代理名称如web type tcp # 我们的Web服务是HTTP/HTTPS基于TCP local_ip 127.0.0.1 # 内网中服务的IP因为frpc和Nginx在同一台机器所以是127.0.0.1 local_port 80 # 内网中服务的端口即Nginx监听的端口 remote_port 6000 # 在公网服务器上暴露的端口外部用户将通过公网IP:6000访问 # 可选增加健康检查 health_check_type tcp health_check_timeout_s 3 health_check_max_failed 3 health_check_interval_s 10这个配置的含义是在公网服务器的6000端口上监听所有发往公网IP:6000的 TCP 连接都会被 frps 通过隧道转发到内网服务器的frpc再由frpc转发到内网服务器的80端口即我们的 Nginx 服务。运行 frpc同样建议使用 Systemd。sudo vim /etc/systemd/system/frpc.service[Unit] DescriptionFrp Client Service Afternetwork.target [Service] Typesimple Usernobody Restarton-failure RestartSec5s ExecStart/opt/frp/frpc -c /opt/frp/frpc.ini [Install] WantedBymulti-user.targetsudo systemctl daemon-reload sudo systemctl enable frpc sudo systemctl start frpc sudo systemctl status frpc5.3 验证与访问确保内网的 Nginx 和 Spring Boot 服务都在正常运行。确保 frps 和 frpc 服务状态都是active (running)。在 frps 的仪表板 (公网IP:7500) 上你应该能看到一个名为[web]的代理处于online状态。现在最关键的一步让外部用户或者你自己在另一个网络下访问http://你的公网服务器IP:6000。如果一切配置正确你应该能看到部署在内网服务器的 Vue 前端页面并且所有 API 请求/api/xxx也能正常工作。深度解析与避坑防火墙连环套这是内网穿透失败的最常见原因。你需要检查三层防火墙a) 公网云服务商的安全组必须开放7000, 7500, 6000端口。b) 公网服务器自身的防火墙如ufw或firewalld。c) 内网服务器的防火墙确保80端口本地可访问。d) 内网路由器的防火墙或NAT设置通常frpc能主动出站连接即可。域名与端口现在我们是通过IP:端口访问不美观且需要记端口。可以在公网服务器上再用一个 Nginx将域名如app.yourdomain.com反向代理到localhost:6000这样用户就可以用http://app.yourdomain.com访问了无需输入端口。HTTPS 加密上述流程是 HTTP。生产环境必须使用 HTTPS。你可以在公网服务器的 Nginx 上配置 SSL 证书从 Let‘s Encrypt 免费获取实现 HTTPS 访问而内网隧道仍然是明文的可在 frp 配置中启用 TLS 加密隧道。稳定性内网穿透的稳定性依赖于公网服务器的网络质量和 frp 隧道。对于重要服务建议选择网络稳定的云服务器并配置 frpc 的auto_reconnect等参数。也可以考虑使用商业化的内网穿透服务它们通常提供更稳定的节点和运维支持。通过以上五个部分的详细拆解我们从零开始完成了一个 Spring Boot Vue 全栈项目从本地开发到服务器部署再到通过内网穿透实现公网访问的完整闭环。每个步骤都包含了原理说明、实操命令和踩坑经验。部署是一个系统工程涉及网络、系统、运行时、应用配置多个层面希望这份详尽的指南能帮你建立起清晰的部署思维顺利将你的项目发布上线。
返回列表