在一台服务器上同时部署前端和后端服务,是中小规模项目、个人开发者或初创团队最常见的架构模式。核心思路非常明确:利用反向X_X(Reverse Proxy)将不同的请求路径分发到不同的端口或服务进程。
以下是几种主流且稳定的实现方案,按推荐程度排序:
方案一:Nginx + Node.js/Python/Go (最经典、最稳定)
这是业界标准做法。Nginx 作为高性能的 HTTP 服务器和反向X_X,负责处理静态资源(前端)并转发动态请求(后端)。
1. 目录结构规划
建议统一在项目根目录下管理,例如 /opt/myproject:
/opt/myproject/
├── frontend/ # 前端构建后的静态文件 (dist/index.html, js/, css/)
├── backend/ # 后端代码及运行环境
│ ├── app.py # 示例:Flask/Django 或 Express 等
│ └── ...
└── nginx.conf # Nginx 配置文件
2. 前端构建与部署
- 开发阶段:使用
npm run build生成静态文件。 - 部署:将生成的
dist文件夹内容复制到服务器指定目录(如/var/www/frontend)。
3. 后端启动
确保后端服务监听在本地非标准端口上(避免冲突),例如 localhost:8080。
- 关键安全点:后端服务必须绑定
127.0.0.1而不是0.0.0.0,防止绕过 Nginx 直接访问后端接口,造成安全隐患。
4. Nginx 配置示例 (/etc/nginx/conf.d/default.conf)
server {
listen 80;
server_name your_domain.com; # 替换为你的域名或 IP
# 前端静态资源
location / {
root /var/www/frontend;
index index.html;
try_files $uri $uri/ /index.html; # Vue/React 路由刷新支持
}
# 后端 API 接口
location /api/ {
proxy_pass http://127.0.0.1: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;
# WebSocket 支持 (如果需要)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 其他特定路径可继续扩展
}
5. 优势
- 性能高:Nginx 处理静态文件能力极强。
- 安全性好:后端不直接暴露给公网。
- 易于维护:前后端解耦,重启后端不影响前端访问。
方案二:Docker Compose (现代化、隔离性好)
如果你希望环境完全隔离、一键部署,推荐使用 Docker Compose。这是当前云原生时代的主流方式。
1. 创建 docker-compose.yml
version: '3.8'
services:
# 前端服务 (基于 Nginx 镜像)
frontend:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./frontend/dist:/usr/share/nginx/html # 挂载前端静态文件
- ./nginx.conf:/etc/nginx/conf.d/default.conf # 挂载自定义 Nginx 配置
depends_on:
- backend
# 后端服务
backend:
build: ./backend # 根据你的语言构建镜像
expose:
- "8080" # 内部通信端口,不直接对外暴露
environment:
- NODE_ENV=production # 或其他环境变量
restart: always
networks:
default:
driver: bridge
2. Nginx 配置 (对应上面的 nginx.conf)
由于前端容器内运行 Nginx,其 location /api/ 需要指向后端容器的服务名:
location /api/ {
proxy_pass http://backend:8080; # 使用 Docker 内部 DNS 解析
# ... 其他 proxy 设置同上
}
3. 启动命令
docker-compose up -d
4. 优势
- 环境一致:开发、测试、生产环境完全一致。
- 依赖管理:自动处理网络和服务依赖。
- 易于迁移:整包迁移到其他服务器只需复制代码和 compose 文件。
方案三:Node.js 单进程托管 (简单但有限制)
如果你的后端也是 Node.js (如 Express/Koa),且项目较小,可以考虑让一个 Node 进程同时提供静态文件和 API。
1. 代码实现 (Express 示例)
const express = require('express');
const path = require('path');
const app = express();
// 1. 提供静态文件 (前端)
app.use(express.static(path.join(__dirname, 'frontend/dist')));
// 2. 定义 API 路由
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from backend' });
});
// 3. 捕获所有非 API 请求,返回前端 index.html (SPA 路由支持)
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'frontend/dist/index.html'));
});
app.listen(8080, () => {
console.log('Server running on port 8080');
});
4. 注意
- 仍需 Nginx/Apache 做前置X_X:即使这样,也强烈建议在前面加一层 Nginx 来处理 HTTPS、Gzip 压缩、静态资源缓存等。否则直接用 Node 监听 80 端口在生产环境中性能和安全都较差。
- 适用场景:超小型项目、原型验证、全栈 JS 团队快速迭代。
关键注意事项与最佳实践
-
HTTPS 证书配置
- 无论哪种方案,最终出口都应通过 Nginx 配置 SSL/TLS 证书。
- 可以使用 Let’s Encrypt 的
certbot自动申请和管理免费证书。
-
进程守护
- 不要直接使用
node app.js或python app.py启动。一旦终端关闭,服务就停了。 - 使用 PM2 (Node.js)、systemd (Linux 通用)、或 Supervisor 来守护后端进程,确保崩溃后自动重启。
- 不要直接使用
-
数据库连接
- 如果数据库也在同一台服务器,使用
127.0.0.1连接,避免网络开销。 - 如果数据库独立部署,确保防火墙允许该服务器 IP 访问数据库端口。
- 如果数据库也在同一台服务器,使用
-
安全加固
- 最小权限原则:运行服务的用户不应是 root。
- 防火墙策略:只开放 80/443 端口,后端端口(如 8080)仅允许本地回环地址访问。
- 防跨域 (CORS):由于前后端同源(同一域名、不同路径),通常不需要复杂 CORS 配置,但需确保后端不随意设置
Access-Control-Allow-Origin: *。
-
监控与日志
- 集中收集 Nginx 访问日志、后端应用日志。
- 使用简单工具如
fail2ban防止暴力破解。
总结建议
- 初学者/小项目:采用 方案一 (Nginx + PM2),配置简单,资源占用低。
- 团队协作/追求标准化:采用 方案二 (Docker Compose),便于版本控制和迁移。
- 避免:直接在云服务器安全组中开放后端端口,或使用无守护进程的裸启方式。
这种架构在国内云计算环境下(如阿里云 ECS、腾讯云 CVM)广泛验证,稳定性高,成本低廉,适合绝大多数非超高并发场景。
CLOUD云枢