使用docker部署koa+sql server+react项目完整过程

前言: ubuntu服务器现在已经用docker启动了一个sql server了,我现在想把本地的koa+sql server+react项目部署到ubuntu中,react前端直接打包上传到服务器通过nginx去访问,后端的话通过docker来部署要怎么搞,主要数据库方面不知道要怎么弄?

目前是:

  • ✅ Ubuntu 服务器已经用 Docker 跑了一个 SQL Server

  • ✅ 本地有:

    • Koa(Node 后端)
    • React(前端)
    • SQL Server(本地开发用)

你想要的最终形态是:

arduino 复制代码
浏览器
  ↓
Nginx(9527 或 80)
  ↓
React 静态文件
  ↓
/api → Nginx → Koa(Docker)
                  ↓
              SQL Server(Docker)

这是完全正确、也是推荐的部署方式。


总体推荐架构

前端不用 Docker,后端 + 数据库用 Docker,Nginx 做统一入口

arduino 复制代码
Ubuntu
├─ nginx(宿主机)
│
├─ /opt/translationfront/        ← React build
│
├─ docker
│   ├─ sqlserver 容器
│   └─ koa-backend 容器
│        |
│        └── 通过 Docker 网络访问 SQL Server

React 前端

本地打包

arduino 复制代码
npm run build

注意 package.json

json 复制代码
{
  "homepage": "translationfront"
}

注意app.js

xml 复制代码
 <Router basename="/translationfront">
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
 </Router>

👉 前端这部分已经结束。


重点来了:后端 + SQL Server 怎么搞(核心)

你已经在 Ubuntu 上用 Docker 跑了 SQL Server

👉 这是非常好的事情

关键原则(先记住)

后端不要再起一个新的 SQL Server

👉 Koa 容器直接连"已经存在的 SQL Server 容器"


最关键的一步:Docker 网络(解决数据库问题)

实际部署过程中发现不需要处理数据库这一步,自动就连上了数据库。

❌ 新手最常犯的错

  • localhost
  • 用服务器公网 IP
  • 端口乱暴露

正确做法:创建一个 docker 网络(只需一次)

lua 复制代码
docker network create oa-net

把 SQL Server 加入这个网络

arduino 复制代码
docker network connect oa-net mssql

新建Dockerfile.backend

bash 复制代码
FROM node:24-alpine
WORKDIR /app

# 复制 package.json 和 package-lock.json 到镜像中
COPY package*.json ./
# 安装生产所需的依赖包,跳过开发依赖;--omit=dev忽略开发依赖;npm ci就是npm clean install
# RUN npm ci --omit=dev

# 安装项目依赖,不跳过开发依赖
RUN npm ci

# 复制 server 目录到镜像中
COPY server/ ./server/

# 创建用户和组,并设置权限
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001 && \
    chown -R nodejs:nodejs /app

USER nodejs

EXPOSE 6051
ENV NODE_ENV=production
ENV PORT=6051

# 指定启动命令
CMD ["node", "server/server.js"]

新建docker-compose.yml

yaml 复制代码
#version: '3.3'

services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile.backend
    ports:
      - "6051:6051"
    restart: unless-stopped

需要上传到服务器的目录文件如下:

csharp 复制代码
server
build #上传到服务器之后改个名字,如:translationfront
package-lock.json
package.json
Dockerfile.backend
docker-compose.yml

服务器目录结构如下:

lua 复制代码
Ubuntu服务器
├─ /opt
    |---ec-translation
                |
            translationfront ← React build
                |
            server
                |
            Dockerfile.backend
               |
            docker-compose.yml
               |
            package.json
               |
            package-lock.json

nginx配置

ini 复制代码
server{
    listen 9527;
    server_name oa.jt-ele.com;
    absolute_redirect off;
    access_log /var/log/nginx/oa.jt-ele.com-port-9527.access.log;
    error_log  /var/log/nginx/oa.jt-ele.com-port-9527.error.log;
  
    #ai翻译应用前端
    location /translationfront {
        root /opt/ec-translation;
        index index.html;
        try_files $uri $uri/ /translationfront/index.html;
    }
    
      #ai翻译应用api服务:代理到 Docker中的 Koa 服务
    location /ecTranslationApi/ {
        proxy_pass http://127.0.0.1:6050;
        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_http_version 1.1;
    }
    
}

路径映射原理:

  1. root:
bash 复制代码
 location /translationfront {
    root /opt/ec-translation;
    index index.html;
    try_files $uri $uri/ /translationfront/index.html;
 }

🔍 root 指令的路径拼接规则

📌 Nginx 的 root 是这样工作的:

root 指定的是"根目录",最终文件路径 = root 路径 + 完整的 URI

也就是说:

  • root /opt/ec-translation;
  • 请求 /translationfront
  • Nginx 实际查找的文件是:/opt/ec-translation/translationfront
  1. alias
bash 复制代码
 location /translationfront {
    alias /opt/ec-translation/translationfront;
    index index.html;
    try_files $uri $uri/ /translationfront/index.html;
 }
🔍 alias 的规则是:

alias替换 location 匹配的部分

所以:

  • location /translationfront
  • alias /opt/ec-translation/translationfront
  • 请求 /translationfront → 实际路径:/opt/ec-translation/translationfront

完美匹配你的文件结构

端口映射原理:为什么没做端口映射,也能访问后端api?

一句话:Nginx在公网端口上"替你转发了请求"

一张图先看全局(非常重要)

less 复制代码
[ 浏览器 ]
    |
    |  http://oa.jt-ele.com:9527/ecTranslationApi/translateText
    |
[ 公网 IP : 9527 ]   ←--------- 只有这个端口是公网开放的
    |
[ Nginx(宿主机) ]
    |
    |  proxy_pass http://127.0.0.1:6050
    |
[ 宿主机 127.0.0.1:6050 ]
    |
[ Docker 端口映射 ]
    |
[ 容器内 Koa :6050 ]

👉 外网只能看到 9527

👉 6050 从来没暴露给公网

三个端口,各自"身份"是什么?

宿主机端口、容器端口、本地项目端口,这些是怎么映射的?

我们一个一个对。


本地项目端口(Koa listen 的端口)

ini 复制代码
app.listen(6050);

这是:

Koa 在"容器内部"监听的端口

⚠️ 它的作用范围:

  • ❌ 外网访问不到
  • ❌ 宿主机也访问不到
  • 只在容器内部有效

容器端口(Docker EXPOSE)

yaml 复制代码
EXPOSE 6050

这一步:

只是"声明"

👉 告诉 Docker:这个容器"打算用"6050

⚠️ 它不会:

  • ❌ 自动暴露端口
  • ❌ 自动对外开放

很多人误以为 EXPOSE 就是"开公网",这是误区


宿主机端口(docker-compose 的 ports)

makefile 复制代码
ports:
  - "6050:6050"

这一步才是真正的「通道建立」:

yaml 复制代码
宿主机 6050  ←→  容器 6050

👉 但注意:

  • 这是宿主机端口
  • 并不等于公网端口

是否公网可访问,取决于 防火墙 / 云厂商 / Nginx


为什么"没开公网端口,也能公网访问"?

答案只有一句话:

因为 Nginx 帮你做了"中转"


你现在的真实情况(代入你的配置)

1️⃣ 公网只开放了一个端口

yaml 复制代码
公网 IP : 9527   ✅

云服务器安全组 / 穿透 / 防火墙只放行了:

yaml 复制代码
9527

2️⃣ Nginx 监听这个公网端口

arduino 复制代码
server {
    listen 9527;

    location /ecTranslationApi/ {
        proxy_pass http://127.0.0.1:6050/;
    }
}

👉 Nginx 是跑在 宿主机上的


3️⃣ 请求"被转发"到了本地 6050

复制代码
Nginx → 127.0.0.1:6050

这里的 127.0.0.1 是:

宿主机自己


4️⃣ Docker 再把请求送进容器

yaml 复制代码
宿主机 6050 → 容器 6050 → Koa

所以"公网访问后端"的真相是

公网访问的根本不是 Koa

公网访问的是 Nginx

Koa 永远躲在内网里

这就是标准生产架构


为什么这种架构是"最安全、最推荐的"?

对比一下 👇

❌ 错误/危险做法

makefile 复制代码
ports:
  - "6050:6050"

并且:

  • 云防火墙直接放行 6050

后果:

  • 外网可以直接打你 Koa
  • 没限流
  • 没日志
  • 没鉴权
  • 极易被扫端口

✅ 你现在的做法(正确)

yaml 复制代码
公网:只开 9527
Nginx:统一入口
后端:内网服务

优势:

  • ✅ 所有接口都能统一加鉴权 / 日志 / 限流
  • ✅ 后端端口永不暴露
  • ✅ 可以随意改后端端口,不影响前端
  • ✅ 可以挂多个后端服务
相关推荐
SadSunset2 小时前
(44)Spring6集成MyBatis3.5(了解即可,大部分用springboot)
java·spring boot·后端
武子康2 小时前
大数据-199 决策树模型详解:节点结构、条件概率视角与香农熵计算
大数据·后端·机器学习
IT_陈寒2 小时前
Python 3.12 性能优化:5 个鲜为人知但提升显著的技巧让你的代码快如闪电
前端·人工智能·后端
短剑重铸之日2 小时前
《深入解析JVM》第四章:JVM 调优
java·jvm·后端·面试·架构
fanruitian2 小时前
SpringBoot 调用springai ollama
java·spring boot·后端
开心猴爷2 小时前
上架苹果App Store时开发者常忽略的15个问题及解决方法
后端
superman超哥2 小时前
Rust Cargo Build 编译流程:从源码到二进制的完整旅程
开发语言·后端·rust·编译流程·cargo build·从源码到二进制
李慕婉学姐2 小时前
Springboot在线阅读平台的设计与实现5yy58005(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
盛小夏2点0版2 小时前
依旧是隐式函数2.0
后端