在本地开发、内网测试或小型项目部署场景中,Vue3 + SpringBoot 是最主流的前后端分离技术栈之一。本文将手把手教你通过编写Dockerfiledocker-compose.yml文件,实现这套技术栈的一键部署,且仅暴露回环端口(127.0.0.1),保证服务仅本机可访问,兼顾便捷性与安全性。

一、场景与技术选型

核心需求

  1. 技术栈:前端 Vue3(Vite 构建) + 后端 SpringBoot 3.x;

  2. 部署方式:Docker 容器化,环境完全隔离;

  3. 网络安全:仅绑定回环地址,避免外网访问;

  4. 运维便捷:一键启动 / 停止,自动处理依赖和网络。

前置准备

  1. 服务器 / 本地环境已安装 Docker 和 Docker Compose;

  2. 已完成 Vue3 前端项目和 SpringBoot 后端项目开发;

  3. 基础的 Docker 命令认知(无需深入,本文全程复制即用)。

二、项目目录结构

先梳理标准化的项目结构,后续所有配置均基于此,建议按此目录组织代码:

vue3-springboot-demo/
├── frontend/          # Vue3前端项目(Vite构建)
│   ├── Dockerfile     # 前端镜像构建文件
│   ├── package.json   # 前端依赖
│   ├── vite.config.js # Vite配置
│   └── dist/          # 打包后的静态文件(npm run build生成)
├── backend/           # SpringBoot后端项目
│   ├── Dockerfile     # 后端镜像构建文件
│   ├── pom.xml        # Maven依赖
│   └── src/           # 后端源码
└── docker-compose.yml # Compose编排文件(核心)

三、编写 Dockerfile(前后端镜像构建)

1. 前端 Dockerfile(Vue3 + Vite)

路径:frontend/Dockerfile

# 阶段1:构建前端静态文件
FROM node:18-alpine as build-stage
WORKDIR /app
# 复制依赖文件(利用Docker缓存,避免每次都重装依赖)
COPY package*.json ./
# 国内镜像源加速安装
RUN npm install --registry=https://registry.npmmirror.com
# 复制全部源码
COPY . .
# 打包构建(Vite构建生产环境包)
RUN npm run build

# 阶段2:使用Nginx部署静态文件(轻量、高性能)
FROM nginx:alpine as production-stage
# 复制构建好的静态文件到Nginx默认目录
COPY --from=build-stage /app/dist /usr/share/nginx/html
# 自定义Nginx配置(解决Vue Router history模式刷新404 + 接口反向代理)
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 暴露容器内部80端口(仅容器内可见)
EXPOSE 80
# 启动Nginx(前台运行,避免容器退出)
CMD ["nginx", "-g", "daemon off;"]

补充:前端 Nginx 配置(关键)

创建frontend/nginx.conf,解决路由问题并代理后端接口:

server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # 解决Vue3 Router history模式刷新404
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 反向代理后端接口(前端请求/api全部转发到后端容器)
    location /api {
        proxy_pass http://backend:8080; # backend是Compose中后端服务名
        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;
    }

    # 静态资源缓存(优化性能)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 7d;
        add_header Cache-Control "public, max-age=604800";
    }
}

2. 后端 Dockerfile(SpringBoot 3.x)

路径:backend/Dockerfile(采用多阶段构建,减小镜像体积)

# 阶段1:构建SpringBoot项目
FROM maven:3.8.5-openjdk-17 as build-stage
WORKDIR /app
# 复制pom.xml和源码
COPY pom.xml ./
COPY src ./src
# 国内镜像源加速打包(替换为阿里云Maven仓库)
RUN mvn clean package -Dmaven.test.skip=true -Dmaven.repo.local=/root/.m2/repository -s /usr/share/maven/ref/settings-docker.xml

# 阶段2:运行SpringBoot项目(轻量JRE镜像)
FROM openjdk:17-jdk-slim
WORKDIR /app
# 从构建阶段复制打包好的jar包
COPY --from=build-stage /app/target/*.jar app.jar
# 暴露后端端口
EXPOSE 8080
# JVM优化参数(可选)
ENV JAVA_OPTS="-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom"
# 启动后端服务
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

后端示例接口(测试用)

在 SpringBoot 项目中编写一个简单接口,用于验证前后端通信:

// com.example.demo.controller.HelloController
package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class HelloController {

    @GetMapping("/hello")
    public Map<String, Object> hello() {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 200);
        result.put("message", "Hello from SpringBoot Backend!");
        result.put("data", "Vue3 + SpringBoot 部署成功");
        return result;
    }
}

SpringBoot 跨域配置(可选)

若未使用 Nginx 代理,需在后端添加跨域配置:

// com.example.demo.config.CorsConfig
package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("http://127.0.0.1:8080");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/**", config);
        return new CorsFilter(source);
    }
}

四、编写 Docker Compose 文件(一键编排)

路径:docker-compose.yml(核心配置,实现一键启动)

version: '3.8'

# 定义服务集合
services:
  # 前端服务
  frontend:
    # 基于前端目录的Dockerfile构建镜像
    build: ./frontend
    # 容器名称(便于管理)
    container_name: vue3-frontend
    # 重启策略:异常崩溃/服务器重启后自动启动(除非手动停止)
    restart: unless-stopped
    # 端口映射:仅绑定回环地址127.0.0.1,主机8080 → 容器80
    # 关键:127.0.0.1限定仅本机可访问,外网无法连接
    ports:
      - "127.0.0.1:8080:80"
    # 依赖后端服务,确保后端先启动
    depends_on:
      - backend
    # 加入自定义网络(前后端容器互通)
    networks:
      - app-network

  # 后端服务
  backend:
    # 基于后端目录的Dockerfile构建镜像
    build: ./backend
    container_name: springboot-backend
    restart: unless-stopped
    # 端口映射:仅绑定回环地址,主机8081 → 容器8080
    ports:
      - "127.0.0.1:8081:8080"
    # 环境变量(可配置数据库地址、端口等)
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SERVER_PORT=8080
    # 自定义网络
    networks:
      - app-network

# 自定义桥接网络(隔离外部网络,仅前后端容器互通)
networks:
  app-network:
    driver: bridge

核心配置说明

  1. 端口映射规则127.0.0.1:主机端口:容器端口

    例如127.0.0.1:8080:80表示:仅本机可通过 8080 端口访问前端容器的 80 端口,外网无法访问,极大提升安全性。

  2. depends_on:保证后端服务先启动,避免前端请求时后端未就绪。

  3. 自定义网络app-network让前后端容器通过服务名(如backend)互通,无需手动配置 IP。

五、一键启动与运维命令

1. 启动服务(核心命令)

vue3-springboot-demo根目录下执行:

# 首次启动:构建镜像 + 启动容器(后台运行)
docker-compose up -d --build

# 后续启动(无需重新构建镜像)
docker-compose up -d
  • -d:后台运行容器,不占用终端;

  • --build:强制重新构建镜像(代码修改后需加此参数)。

2. 验证服务是否正常

# 查看容器运行状态
docker-compose ps

# 查看前端日志(排查前端问题)
docker-compose logs -f frontend

# 查看后端日志(排查后端问题)
docker-compose logs -f backend

# 测试后端接口(本机访问)
curl http://127.0.0.1:8081/api/hello

若返回如下 JSON,说明后端正常:

{"code":200,"data":"Vue3 + SpringBoot 部署成功","message":"Hello from SpringBoot Backend!"}

前端访问:打开浏览器输入 http://127.0.0.1:8080,即可看到 Vue3 页面,且能正常调用后端接口。

3. 常用运维命令

# 停止服务(保留容器,可重启)
docker-compose stop

# 重启服务
docker-compose restart

# 停止并删除容器(保留镜像)
docker-compose down

# 停止并删除容器 + 镜像(彻底清理)
docker-compose down --rmi all

# 查看容器资源占用
docker stats vue3-frontend springboot-backend

六、常见问题排查

1. 前端无法访问后端接口?

  • 检查 Nginx 配置中的proxy_pass是否为http://backend:8080(后端服务名 + 容器端口);

  • 确认后端服务监听地址为0.0.0.0(SpringBoot 默认就是,无需修改);

  • 查看前端容器日志:docker-compose logs frontend,检查 Nginx 是否启动正常。

2. 构建镜像时依赖下载慢?

  • 前端:在package.json中使用国内 npm 镜像(registry=https://registry.npmmirror.com);

  • 后端:在pom.xml中添加阿里云 Maven 镜像源。

3. 端口被占用?

修改docker-compose.yml中的主机端口,例如将127.0.0.1:8080:80改为127.0.0.1:8082:80

七、总结

  1. 通过Dockerfile实现 Vue3/SpringBoot 的镜像标准化构建,解决了 “环境不一致” 的经典问题;

  2. docker-compose.yml实现一键编排,自动处理容器依赖、网络、端口映射,大幅降低部署复杂度;

  3. 端口映射绑定127.0.0.1,仅允许本机访问,在开发 / 测试环境中兼顾便捷性与安全性。

这套方案适用于本地开发、内网测试、小型个人项目部署,无需手动配置 Nginx、JDK、Node.js 等环境,真正做到 “一次编写,到处运行”。