主题
14.3.4 部署前后端分离应用
本节目标:掌握前后端分离架构的通用部署流程,学会用 Claude Code 辅助配置反向代理,适用于任何技术栈(Node.js / Python / PHP / Java / Go / .NET 等)。
本节与 14.3.2 的区别
- 14.3.2:适合 Next.js 这种"前后端一体"的全栈框架,一个容器搞定
- 本节(14.3.4):适合"前后端分离"的架构,前端和后端是独立的项目,需要分别部署
如果你的项目是 Next.js/Nuxt 等全栈框架,直接看 14.3.2 即可。如果你的前端是 React/Vue,后端是独立的 API 服务(Node.js/Python/Java 等),那就需要本节的方案。
小明的全栈项目有前端、后端 API、数据库三个部分。"之前在 Vercel 上是一个项目搞定,现在要分开部署?"
老师傅说:"Vercel 帮你把这些打包在一起了,但在自己的服务器上,你需要理解它们各自的角色。好处是——你对每一层都有完全的控制权。"
他画了一张图:"前后端分离的架构长这样——"
前后端分离架构
用户浏览器
│
▼
OpenResty(反向代理):80
│
├── / → 前端静态文件(HTML/CSS/JS)
├── /api/* → 后端服务(容器端口 3000/8000/8080...)
│
└── 后端服务
│
▼
数据库(PostgreSQL/MySQL/MongoDB...)三个服务各司其职:
- OpenResty:对外的唯一入口,负责分发请求
- 后端服务:处理业务逻辑和数据库操作(Node.js / Python / Java / Go 等)
- 数据库:存储数据
什么是反向代理?
反向代理就像一个"前台接待员":
- 用户的所有请求都先到前台(OpenResty)
- 前台看请求的路径,决定转给谁处理:
- 访问
/→ 返回前端页面 - 访问
/api/users→ 转发给后端服务
- 访问
- 用户感觉只和一个服务器打交道,但背后可能有多个服务在协作
好处:
- 统一入口:用户只需要记一个域名
- 避免跨域:前端和 API 在同一个域名下
- 安全:后端服务不直接暴露在公网
小明画了一张简单的图:用户请求先到 OpenResty,OpenResty 看路径——如果是 /api 开头就转给后端,其他的就返回前端页面。"原来 Vercel 在背后也是这么干的,只不过它帮我把这些全藏起来了。"
它们都运行在 Docker 容器里,通过容器网络互相通信。
通用部署流程
无论你的后端是什么技术栈,部署流程都是类似的:
第一步:部署数据库
根据项目需求,在 1Panel 应用商店安装对应的数据库:
- PostgreSQL:适合关系型数据、复杂查询
- MySQL:适合传统 Web 应用
- MongoDB:适合文档型数据
- Redis:适合缓存、会话存储
安装完成后,创建应用专用数据库和用户,记下连接信息(主机名、端口、用户名、密码)。
1Panel 数据库容器命名规则
1Panel 创建的数据库容器名遵循 1Panel-{数据库类型}-{随机4位字母} 的格式:
- PostgreSQL:
1Panel-postgresql-ukow - Redis:
1Panel-redis-w94p - MySQL:
1Panel-mysql-abcd - MongoDB:
1Panel-mongodb-xyz1
如何查看实际的容器名: 在 1Panel 的「容器」页面,列表的第一列就是容器名。你也可以在「数据库」页面点击对应数据库的「详情」查看连接信息。
后端应用通过容器名(而非 localhost)连接数据库。
常见数据库连接字符串示例
PostgreSQL:
bash
DATABASE_URL="postgresql://用户名:密码@1Panel-postgresql-ukow:5432/数据库名"MySQL:
bash
DATABASE_URL="mysql://用户名:密码@1Panel-mysql-abcd:3306/数据库名"Redis(有密码):
bash
REDIS_URL="redis://:密码@1Panel-redis-w94p:6379"Redis(无密码):
bash
REDIS_URL="redis://1Panel-redis-w94p:6379"MongoDB:
bash
MONGODB_URI="mongodb://用户名:密码@1Panel-mongodb-xyz1:27017/数据库名"第二步:部署后端服务
根据后端技术栈选择部署方式:
| 技术栈 | 1Panel 运行环境(语言) | 启动命令参考 |
|---|---|---|
| Node.js / Next.js | Node.js | git pull && pnpm build && pnpm start |
| Python / FastAPI | Python | git pull && pip install -r requirements.txt && uvicorn main:app --host 0.0.0.0 |
| PHP / Laravel | PHP | PHP-FPM 自动启动,通过 OpenResty 反向代理访问 |
| Java / Spring Boot | Java | java -jar app.jar |
| Go | Go | ./app |
| .NET / ASP.NET Core | .NET | dotnet run --urls http://0.0.0.0:5000 |
运行环境 = Docker 容器
1Panel 的「运行环境」本质上是 Docker 容器。每种语言(Node.js、Python、PHP、Java、Go、.NET)对应一个预配置好的基础镜像,你选择语言和版本后,1Panel 会用 docker-compose 帮你管理容器的创建和启动。
关键配置:
- 环境变量:数据库连接字符串、密钥等
- 端口映射:在高级配置中,把容器内部端口(如 3000)映射到服务器外部端口(如 3001)
- 启动命令:确保每次重启时自动拉取最新代码
- 容器名称:用于容器间通信(如反向代理通过容器名转发请求)
小明的项目是 Node.js,他在「运行环境」中创建了一个容器,填了项目目录、启动命令、环境变量。几分钟后,后端 API 跑起来了。他在浏览器访问 http://服务器IP:3001/api/health,看到了 JSON 响应。
第三步:构建并部署前端
前端通常需要先在本地构建,然后上传到服务器:
bash
# 在本地电脑上
cd your-project
# 设置环境变量(指向服务器的后端 API)
echo "VITE_API_URL=http://你的服务器IP:3001" > .env.production
# 构建前端
npm run build # 或 pnpm build / yarn build
# 构建产物通常在 dist/ 或 build/ 或 out/ 目录上传到服务器:
bash
# 方式一:使用 scp
scp -r dist/* root@你的服务器IP:/opt/your-frontend/
# 方式二:使用 FinalShell 拖拽上传在 1Panel 中创建静态网站:
- 进入「网站 > 网站」,点击「创建网站」
- 选择「静态网站」
- 主域名:
yourdomain.com(或先用 IP 测试) - 网站目录:
/opt/your-frontend - 点击确认
小明用 FinalShell 把构建好的前端文件拖到服务器上,然后在 1Panel 创建了静态网站。浏览器访问服务器 IP,前端页面出来了——但他试着登录,发现报错:"跨域请求被阻止"。
第四步:配置反向代理(关键步骤)
现在前端和后端是分开的——前端在 80 端口,后端在 3001 端口。前端发起的 API 请求会遇到跨域问题。解决方案是配置反向代理,让前端和后端在同一个域名下。
推荐工作流:让 Claude Code 帮你写配置
- 获取 1Panel 的默认配置
在 1Panel 中,进入刚创建的静态网站的设置页面,点击「配置文件」选项卡,复制整个配置内容。
- 在本地用 Claude Code 完善配置
打开本地的 Claude Code,发送以下 prompt:
我需要配置 OpenResty 反向代理,实现前后端分离部署。
当前 1Panel 默认配置:
[粘贴你复制的配置]
我的需求:
- 前端静态文件在 /opt/your-frontend
- 后端 API 容器名是 your-backend,端口 3000
- 所有 /api/* 请求转发到后端
- 其他请求返回前端页面(SPA 路由支持)
请帮我完善这个配置。Claude Code 会根据你的实际情况生成完整的配置,包括:
- 正确的
proxy_pass地址 - 必要的请求头设置
- 超时配置
- SPA 路由支持(
try_files)
- 复制回服务器
把 Claude Code 生成的配置复制回 1Panel 的「配置文件」编辑框,点击「保存并重载」。
小明把 1Panel 的默认配置复制到本地 Claude Code,说明了自己的需求。Claude Code 很快生成了完整的配置,包括反向代理规则、请求头设置、超时配置。小明复制回 1Panel,点击保存——刷新浏览器,这次登录成功了!
为什么推荐这个工作流?
- Claude Code 理解你的项目:它知道你的容器名、端口、路由结构
- 避免手动出错:容器名拼写错误、路径配置错误是常见问题
- 自动补全细节:超时设置、请求头、错误处理等容易遗漏的配置
- 可以反复调整:配置不对可以继续让 Claude Code 修改
如果 Claude Code 生成的配置有问题怎么办?
- 查看错误日志:在「应用商店 → 已安装 → OpenResty」中查看错误日志
- 把错误信息发给 Claude Code:复制错误日志,告诉 Claude Code "我的反向代理配置有问题,错误日志是..."
- Claude Code 会帮你修正:它会分析错误原因,生成修正后的配置
- 常见错误:
- 容器名拼写错误 → 检查容器名是否正确
- 端口号错误 → 检查后端服务的实际端口
- 路径配置错误 → 检查
proxy_pass的路径是否正确
如果多次尝试仍然失败,可以参考本节末尾的"典型的反向代理配置示例"手动修改。
典型的反向代理配置示例
Claude Code 生成的配置通常长这样:
nginx
server {
listen 80;
server_name yourdomain.com;
# 前端静态文件
location / {
root /opt/your-frontend;
try_files $uri $uri/ /index.html; # SPA 路由支持
}
# 后端 API 反向代理
location /api/ {
proxy_pass http://your-backend: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_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}第五步:更新前端 API 地址
反向代理配置好后,前端的 API 地址应该改成相对路径(因为前端和后端在同一个域名下了):
bash
# 在本地电脑上
echo "VITE_API_URL=/api" > .env.production # 或 NEXT_PUBLIC_API_URL=/api
# 重新构建
npm run build
# 重新上传到服务器
scp -r dist/* root@你的服务器IP:/opt/your-frontend/小明重新构建并上传了前端。刷新浏览器,所有功能都正常了——"前端、后端、数据库,三个部分在自己的服务器上协同工作了。"
不同技术栈的差异点
虽然部署流程类似,但不同技术栈有一些细节差异:
Node.js / Next.js
- 运行环境语言:Node.js
- 版本选择:选择和本地一致的 Node.js 版本(最新版本 24.10.0)
- 启动命令:
pnpm build && pnpm start - 端口:通常 3000
- 环境变量:
DATABASE_URL、NODE_ENV=production
Python / FastAPI
- 运行环境语言:Python
- 版本选择:选择和本地一致的 Python 版本(最新版本 3.14.0)
- 启动命令:
pip install -r requirements.txt && uvicorn main:app --host 0.0.0.0 --port 8000 - 端口:通常 8000
- 环境变量:
DATABASE_URL、PYTHONUNBUFFERED=1
PHP / Laravel
- 运行环境语言:PHP
- 版本选择:选择和项目要求一致的 PHP 版本(最新版本 8.5.2)
- 部署方式:PHP 运行环境提供 PHP-FPM 服务(默认端口 9000),需要配合 OpenResty 使用
- 启动命令:PHP-FPM 自动启动,无需配置启动命令
- 环境变量:
DB_CONNECTION、DB_HOST(填容器名)、APP_ENV=production - 注意:PHP 项目通常通过 OpenResty 反向代理到 PHP-FPM,而不是独立运行 HTTP 服务器
Java / Spring Boot
- 运行环境语言:Java
- 版本选择:选择和项目一致的 JDK 版本(最新版本 22)
- 启动命令:
java -jar app.jar - 端口:通常 8080
- 环境变量:
SPRING_DATASOURCE_URL、SPRING_PROFILES_ACTIVE=prod
Go
- 运行环境语言:Go
- 版本选择:选择和项目一致的 Go 版本(最新版本 1.25)
- 启动命令:
./app - 端口:自定义(如 8080)
- 环境变量:根据项目自定义
.NET / ASP.NET Core
- 运行环境语言:.NET
- 版本选择:选择和项目一致的 .NET 版本(最新版本 10.0)
- 启动命令:
dotnet run --urls http://0.0.0.0:5000 - 端口:通常 5000
- 环境变量:
ConnectionStrings__DefaultConnection、ASPNETCORE_ENVIRONMENT=Production
测试完整流程
部署完成后,测试以下功能确保一切正常:
- 访问首页:
http://你的服务器IP→ 看到前端页面 - API 请求:前端发起的 API 请求能正常返回数据
- 数据持久化:刷新页面后数据仍然存在
- 用户认证:登录、退出、权限验证等功能正常
小明把这些功能都测试了一遍,全部正常。他打开开发者工具的 Network 面板,看到前端页面是从 / 加载的,API 请求是发往 /api/xxx 的——"用户完全感觉不到后面有三个服务在跑。"
常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 前端页面打不开 | 安全组没开 80 端口 | 去云厂商控制台开放 80 端口 |
| API 请求 404 | 反向代理配置错误 | 检查 proxy_pass 的容器名和路径 |
| API 请求 502 | 后端容器没启动 | 在「运行环境」中查看日志,重启容器 |
| 数据库连接失败 | DATABASE_URL 主机名填错 | 用容器名(如 postgresql)替代 localhost |
| 跨域错误 | 反向代理未生效 | 确认 OpenResty 配置已保存并重载 |
| SPA 路由 404 | 缺少 try_files 配置 | 让 Claude Code 补充 SPA 路由支持 |
遇到问题时的调试流程
- 先看日志:在「容器」或「运行环境」中查看日志,90% 的问题日志里有答案
- 检查容器状态:确认所有容器都在运行中
- 测试容器间通信:进入后端容器终端,
ping postgresql测试网络连通性 - 让 Claude Code 帮忙:把错误日志发给 Claude Code,让它帮你分析
架构优势总结
通过前后端分离部署,你获得了:
- 统一入口:用户只需要记一个域名,不需要知道后端在哪个端口
- 避免跨域:前端和 API 在同一个域名下,不存在跨域问题
- 安全:后端服务不直接暴露在公网,只有 OpenResty 对外
- 灵活扩展:前端、后端、数据库可以独立升级和扩容
- 完全控制:你对每一层都有完全的控制权,不受平台限制
小明回想起在 Vercel 上部署时,一个 vercel deploy 就搞定了。现在虽然步骤多了,但他理解了每一步在做什么——"Vercel 帮我做的事情,我现在自己也能做了。而且有 Claude Code 帮忙写配置,也没那么难。"
下一步
应用部署完成了,但现在只能通过 IP 访问,不够专业。接下来配置域名和 HTTPS——14.4 配置域名与证书。
