努力
加油

单服务器环境下如何配置前后端共存?

在单服务器环境下实现前后端共存,核心思路其实就一句话:前端静态资源由 Nginx(或 Apache)直接提供,后端 API 请求通过反向XX转发给 Node.js/Python/Java 等运行环境。

不要搞什么“前端打包后塞进后端项目目录让后端渲染”这种老派做法,除非你用的是 PHP 这种天生全栈的语言。现代 Web 开发(Vue/React/Angular + Spring Boot/Go/Node),最标准、性能最好、维护最清晰的方案就是 Nginx 做反向XX。

下面我以国内云服务器(阿里云 ECS、腾讯云 CVM 等)最常见的 Linux 环境(CentOS 7/8 或 Ubuntu 20.04+)为例,讲清楚怎么配。假设你的后端跑在 http://localhost:3000,前端静态文件在 /var/www/html。


一、 架构逻辑图解

用户浏览器
    ↓ (请求 /api/xxx)
Nginx (监听 80/443)
    ├── 匹配到静态文件 (.js, .css, .html, img...) → 直接从磁盘读取返回
    └── 匹配到 /api/* → proxy_pass 转发到 localhost:3000 (你的后端服务)

这样做的好处:

  1. 动静分离:Nginx 处理静态文件的速度是毫秒级的,不占用后端 CPU。
  2. 跨域解决:同源策略下,前端和后端如果在不同端口,会有 CORS 问题。通过 Nginx 统一暴露 80 端口,前端看到的都是同一个域名,天然解决跨域。
  3. 安全性:后端服务不需要直接暴露在公网,只监听本地回环地址(127.0.0.1)。

二、 具体配置步骤(以 Nginx 为例)

1. 准备环境

确保你已经安装了 Nginx,并且你的后端服务已经启动并监听在 127.0.0.1:3000(或其他端口)。

2. 放置前端代码

将前端构建好的 dist 或 build 文件夹内容,上传到服务器的一个目录,比如 /usr/share/nginx/html 或者你自己定义的 /var/www/myapp/frontend。

注意:如果你用的是 Vue/React,记得在构建时设置好 publicPath 或 base,通常默认是 / 即可。如果部署在非根路径,需要调整。

3. 编写 Nginx 配置文件

找到你的 Nginx 配置文件,通常在 /etc/nginx/nginx.conf 或者 /etc/nginx/conf.d/default.conf。建议新建一个文件如 /etc/nginx/conf.d/app.conf,然后在主配置中 include 它。

以下是生产环境推荐的完整配置模板:

server {
    listen 80;
    server_name your_domain.com; # 换成你的域名或 IP

    # 前端静态资源目录
    root /var/www/myapp/frontend;
    index index.html;

    # 1. 处理 SPA 路由(Vue/React History 模式必备)
    # 如果访问的路径不是物理文件,就返回 index.html,让前端 JS 去处理路由
    location / {
        try_files $uri $uri/ /index.html;

        # 可选:开启 gzip 压缩,提升加载速度
        gzip on;
        gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/json image/png image/jpeg;
    }

    # 2. 后端 API 反向XX
    # 假设后端接口前缀是 /api
    location /api/ {
        # 转发到后端服务
        proxy_pass http://127.0.0.1:3000/; 
        # 注意:proxy_pass 后面的 URL 末尾是否有斜杠很重要!
        # 如果有斜杠,Nginx 会去掉 /api/ 这部分再转发,后端收到的是 /users
        # 如果没有斜杠,Nginx 会把 /api/users 完整转发给后端

        # 传递真实的客户端信息给后端
        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_read_timeout 60s;
    }

    # 3. 其他静态资源缓存优化(可选)
    location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

4. 关键细节解析

  • try_files $uri $uri/ /index.html;
    这是单页应用(SPA)的标配。当你刷新 /user/profile 这个页面时,Nginx 会在磁盘里找有没有叫 profile 的文件,找不到就会 fallback 到 index.html。这样前端 Router 才能接管路由,否则你会看到 404 Not Found。

  • proxy_pass 后的斜杠陷阱

    • location /api/ + proxy_pass http://backend/;
      请求 /api/users/list -> 后端收到 /users/list
    • location /api/ + proxy_pass http://backend;
      请求 /api/users/list -> 后端收到 /api/users/list

    根据你的后端代码怎么写来决定。通常为了干净,后端希望去掉 /api 前缀,所以推荐带斜杠写法,或者在后端代码里用中间件剥离前缀。

  • WebSocket 支持(如果需要)
    如果你的前后端通信用了 WebSocket,需要在 location /ws/ 或全局添加以下配置:

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

三、 常见坑与排查

  1. 502 Bad Gateway

    • 原因:Nginx 能连上,但后端挂了或者没启动。
    • 检查:curl http://127.0.0.1:3000/api/test 看后端是否响应。
    • 检查:防火墙是否放行了 3000 端口?(其实只要监听 127.0.0.1,防火墙不需要放行 3000,只需要放行 80/443)。
  2. 前端刷新 404

    • 原因:忘记加 try_files,或者 root 路径写错了。
    • 检查:ls -l /var/www/myapp/frontend/index.html 确保文件存在且 Nginx 用户有读权限。
  3. CORS 错误还在?

    • 原因:你可能把 API 请求写成了直接发往 localhost:3000 而不是走 Nginx 的 /api 路径。
    • 解决:前端 Axios/Fetch 的请求 URL 必须改为相对路径 /api/xxx 或绝对路径 http://yourdomain.com/api/xxx。
  4. HTTPS 配置

    • 现在没有 HTTPS 的网站会被浏览器标记为“不安全”。
    • 推荐使用 Let’s Encrypt 免费证书(certbot),或者云厂商提供的 SSL 证书管理功能。
    • 配置 HTTPS 只需在 Nginx 中添加 listen 443 ssl; 并指定证书路径,然后将 HTTP 重定向到 HTTPS 即可。

四、 进阶:如果用 Docker 呢?

现在很多团队喜欢用 Docker Compose 部署。原理一样,只是容器化。

docker-compose.yml 示例:

version: '3'
services:
  frontend:
    image: nginx:alpine
    volumes:
      - ./frontend/dist:/usr/share/nginx/html
      - ./nginx/conf.d:/etc/nginx/conf.d
    ports:
      - "80:80"
    depends_on:
      - backend

  backend:
    build: ./backend
    expose:
      - "3000"
    # 注意:这里不要映射 3000 到宿主机,只暴露给 docker 内部网络

然后 Nginx 容器里的 proxy_pass 指向 http://backend:3000(因为它们在同一个 Docker 网络里)。


总结

单服务器前后端共存,Nginx 反向XX是唯一正解。

  • 前端:交给 Nginx 当静态服务器。
  • 后端:隐藏在内网,通过 Nginx 透传请求。
  • 配置重点:搞定 SPA 路由的 try_files 和 API XX的 proxy_pass 路径匹配。

别整那些花里胡哨的框架内置服务器托管静态文件的玩法,Nginx 在处理并发和静态资源上的优势是原生进程无法比拟的。配好一次,稳如老狗。