华为云 ECS + Docker + Nginx 部署前后端分离项目实战

举报
yd_264475214 发表于 2026/10/29 10:38:12 2026/10/29
【摘要】 以华为云 ECS 为例,使用 Docker Compose 编排 Node.js 后端与 Nginx 前端,完成前后端分离项目从服务器初始化、反向代理到域名 HTTPS 的完整部署,并整理常见问题排查表。

写在前面

前后端分离项目在本地开发很顺畅,真正上线时却常常被这些问题卡住:服务器端口不通、静态资源 404、接口 502、刷新页面白屏。本文以华为云弹性云服务器 ECS 为例,用 Docker Compose 管理 Node.js 后端和 Nginx 前端,记录一次可复用的部署过程。

适合人群:有一台云服务器、了解基本 Linux 命令、想把个人项目部署上线的开发者。

一、准备清单

  • 华为云 ECS 一台:Ubuntu 22.04,2 核 4G 起步,绑定弹性公网 IP
  • 安全组入方向放通 22(SSH)、80(HTTP)、443(HTTPS)
  • 一个完成备案的域名(国内节点需要)
  • 本地构建好的前端 dist 目录和后端代码

这里有个容易忽略的点:后端 3000 端口不要对公网开放。浏览器所有请求都走 Nginx 同域转发,既少暴露一个端口,也顺带解决了跨域。

二、初始化服务器

SSH 登录后先更新系统并安装 Docker:

sudo apt update && sudo apt upgrade -y
sudo apt install -y docker.io docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker $USER

执行完最后一条需要重新登录,组权限才会生效。验证:

docker version
docker compose version

三、规划目录结构

把部署相关文件集中在一个目录,后续迁移或备份都方便:

/deploy
├── docker-compose.yml
├── nginx
│   └── default.conf
└── web
    └── dist          # 前端构建产物

四、后端容器化

在项目根目录添加 Dockerfile:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

npm ci 比 npm install 更适合构建镜像,它会严格按照 lock 文件安装,构建结果可复现。构建并打上明确版本号:

docker build -t demo-api:1.0 .

不建议使用 latest 标签,回滚时你会感谢版本号。

后端最好再提供一个健康检查接口,例如 /api/health 返回 {"status":"ok"},后面排查问题会用到。

五、配置 Nginx

nginx/default.conf:

server {
    listen 80;
    server_name example.com;

    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass http://api:3000/api/;
        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_read_timeout 60s;
    }

    gzip on;
    gzip_types text/css application/javascript application/json image/svg+xml;
}

两个关键点:

  1. try_files ... /index.html 是 history 路由不白屏的原因。刷新 /user/123 时服务器找不到对应文件,要回退给前端路由处理。
  2. proxy_pass 末尾的斜杠会影响路径拼接。写成 http://api:3000/api/ 时,请求 /api/user 会被转发为 /api/user;去掉末尾斜杠则行为不同。上线前用 curl 确认一次最稳妥。

六、编写 docker-compose.yml

services:
  api:
    image: demo-api:1.0
    restart: always
    environment:
      - NODE_ENV=production
    expose:
      - "3000"

  web:
    image: nginx:1.27-alpine
    restart: always
    ports:
      - "80:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
      - ./web/dist:/usr/share/nginx/html:ro
    depends_on:
      - api

说明:

  • expose 只把端口暴露给 Compose 内部网络,不映射到宿主机,外网无法直接访问。
  • 配置和静态资源都以只读方式挂载,容器内进程无法误改文件。
  • depends_on 只保证启动顺序,不保证后端已就绪,生产环境可以再加健康检查或启动重试脚本。

七、启动与验证

docker compose up -d
docker compose ps
curl -I http://127.0.0.1
curl http://127.0.0.1/api/health

按顺序检查:容器是否 Up、Nginx 是否返回 200、接口是否返回健康状态。最后用浏览器访问公网 IP 或域名。

常见问题对照:

现象 可能原因 排查方向
502 Bad Gateway 后端未启动或服务名写错 docker compose logs api
静态资源 404 dist 路径挂载错误 检查 volume 与 root
刷新页面白屏 缺少 history 回退 检查 try_files
接口跨域 前端直连了后端地址 改为同域 /api 反代
连接超时 安全组未放通 80 检查入方向规则

八、绑定域名与 HTTPS

域名解析添加 A 记录指向 ECS 公网 IP,然后在华为云申请或上传 SSL 证书。Nginx 增加 443 配置,并把 80 跳转到 443:

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate     /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/privkey.pem;
    # 其余配置同上
}

证书文件同样以只读方式挂载进容器。改完配置执行:

docker compose exec web nginx -t
docker compose restart web

先 nginx -t 校验语法,再重启,能避免配置写错导致服务直接不可用。

九、几条实践建议

第一,镜像和依赖都锁定版本,方便回滚。第二,挂载配置和静态资源时加 :ro,减少误操作。第三,给容器日志设置大小上限,避免日志把磁盘写满:

logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

第四,安全组遵循最小开放原则,只放通必要端口。第五,把构建、传输、重启写成脚本或接入 CI/CD,手动部署的次数越少,出错概率越低。

总结

这套方案的核心只有三件事:Nginx 负责入口与静态资源,后端只在内网通信,Docker Compose 把两者编排在一起。先把单机部署跑通,再考虑负载均衡、多副本和自动化发布,路径会清晰很多。

如果这篇文章帮你少踩一个坑,欢迎在评论区交流你的部署经历。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。