本节目标:掌握前后端分离架构的通用部署流程,学会用 Claude Code 辅助配置反向代理,适用于任何技术栈(Node.js / Python / PHP / Java / Go / .NET 等)。
如果你的项目是 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...)
三个服务各司其职:
反向代理就像一个"前台接待员":
/ → 返回前端页面/api/users → 转发给后端服务好处:
小明画了一张简单的图:用户请求先到 OpenResty,OpenResty 看路径——如果是 /api 开头就转给后端,其他的就返回前端页面。"原来 Vercel 在背后也是这么干的,只不过它帮我把这些全藏起来了。"
它们都运行在 Docker 容器里,通过容器网络互相通信。
无论你的后端是什么技术栈,部署流程都是类似的:
根据项目需求,在 1Panel 应用商店安装对应的数据库:
安装完成后,创建应用专用数据库和用户,记下连接信息(主机名、端口、用户名、密码)。
1Panel 创建的数据库容器名遵循 1Panel-{数据库类型}-{随机4位字母} 的格式:
1Panel-postgresql-ukow1Panel-redis-w94p1Panel-mysql-abcd1Panel-mongodb-xyz1如何查看实际的容器名:
在 1Panel 的「容器」页面,列表的第一列就是容器名。你也可以在「数据库」页面点击对应数据库的「详情」查看连接信息。
后端应用通过容器名(而非 localhost)连接数据库。
PostgreSQL:
DATABASE_URL="postgresql://用户名:密码@1Panel-postgresql-ukow:5432/数据库名"
MySQL:
DATABASE_URL="mysql://用户名:密码@1Panel-mysql-abcd:3306/数据库名"
Redis(有密码):
REDIS_URL="redis://:密码@1Panel-redis-w94p:6379"
Redis(无密码):
REDIS_URL="redis://1Panel-redis-w94p:6379"
MongoDB:
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 |
1Panel 的「运行环境」本质上是 Docker 容器。每种语言(Node.js、Python、PHP、Java、Go、.NET)对应一个预配置好的基础镜像,你选择语言和版本后,1Panel 会用 docker-compose 帮你管理容器的创建和启动。
关键配置:
小明的项目是 Node.js,他在「运行环境」中创建了一个容器,填了项目目录、启动命令、环境变量。几分钟后,后端 API 跑起来了。他在浏览器访问 http://服务器IP:3001/api/health,看到了 JSON 响应。
前端通常需要先在本地构建,然后上传到服务器:
# 在本地电脑上
cd your-project
# 设置环境变量(指向服务器的后端 API)
echo "VITE_API_URL=http://你的服务器IP:3001" > .env.production
# 构建前端
npm run build # 或 pnpm build / yarn build
# 构建产物通常在 dist/ 或 build/ 或 out/ 目录
上传到服务器:
# 方式一:使用 scp
scp -r dist/* root@你的服务器IP:/opt/your-frontend/
# 方式二:使用 FinalShell 拖拽上传
在 1Panel 中创建静态网站:
yourdomain.com(或先用 IP 测试)/opt/your-frontend小明用 FinalShell 把构建好的前端文件拖到服务器上,然后在 1Panel 创建了静态网站。浏览器访问服务器 IP,前端页面出来了——但他试着登录,发现报错:"跨域请求被阻止"。
现在前端和后端是分开的——前端在 80 端口,后端在 3001 端口。前端发起的 API 请求会遇到跨域问题。解决方案是配置反向代理,让前端和后端在同一个域名下。
在 1Panel 中,进入刚创建的静态网站的设置页面,点击「配置文件」选项卡,复制整个配置内容。
打开本地的 Claude Code,发送以下 prompt:
我需要配置 OpenResty 反向代理,实现前后端分离部署。
当前 1Panel 默认配置:
[粘贴你复制的配置]
我的需求:
- 前端静态文件在 /opt/your-frontend
- 后端 API 容器名是 your-backend,端口 3000
- 所有 /api/* 请求转发到后端
- 其他请求返回前端页面(SPA 路由支持)
请帮我完善这个配置。
Claude Code 会根据你的实际情况生成完整的配置,包括:
proxy_pass 地址try_files)把 Claude Code 生成的配置复制回 1Panel 的「配置文件」编辑框,点击「保存并重载」。
小明把 1Panel 的默认配置复制到本地 Claude Code,说明了自己的需求。Claude Code 很快生成了完整的配置,包括反向代理规则、请求头设置、超时配置。小明复制回 1Panel,点击保存——刷新浏览器,这次登录成功了!
proxy_pass 的路径是否正确如果多次尝试仍然失败,可以参考本节末尾的"典型的反向代理配置示例"手动修改。
Claude Code 生成的配置通常长这样:
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 地址应该改成相对路径(因为前端和后端在同一个域名下了):
# 在本地电脑上
echo "VITE_API_URL=/api" > .env.production # 或 NEXT_PUBLIC_API_URL=/api
# 重新构建
npm run build
# 重新上传到服务器
scp -r dist/* root@你的服务器IP:/opt/your-frontend/
小明重新构建并上传了前端。刷新浏览器,所有功能都正常了——"前端、后端、数据库,三个部分在自己的服务器上协同工作了。"
虽然部署流程类似,但不同技术栈有一些细节差异:
pnpm build && pnpm startDATABASE_URL、NODE_ENV=productionpip install -r requirements.txt && uvicorn main:app --host 0.0.0.0 --port 8000DATABASE_URL、PYTHONUNBUFFERED=1DB_CONNECTION、DB_HOST(填容器名)、APP_ENV=productionjava -jar app.jarSPRING_DATASOURCE_URL、SPRING_PROFILES_ACTIVE=prod./appdotnet run --urls http://0.0.0.0:5000ConnectionStrings__DefaultConnection、ASPNETCORE_ENVIRONMENT=Production部署完成后,测试以下功能确保一切正常:
http://你的服务器IP → 看到前端页面小明把这些功能都测试了一遍,全部正常。他打开开发者工具的 Network 面板,看到前端页面是从 / 加载的,API 请求是发往 /api/xxx 的——"用户完全感觉不到后面有三个服务在跑。"
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 前端页面打不开 | 安全组没开 80 端口 | 去云厂商控制台开放 80 端口 |
| API 请求 404 | 反向代理配置错误 | 检查 proxy_pass 的容器名和路径 |
| API 请求 502 | 后端容器没启动 | 在「运行环境」中查看日志,重启容器 |
| 数据库连接失败 | DATABASE_URL 主机名填错 |
用容器名(如 postgresql)替代 localhost |
| 跨域错误 | 反向代理未生效 | 确认 OpenResty 配置已保存并重载 |
| SPA 路由 404 | 缺少 try_files 配置 |
让 Claude Code 补充 SPA 路由支持 |
ping postgresql 测试网络连通性通过前后端分离部署,你获得了:
小明回想起在 Vercel 上部署时,一个 vercel deploy 就搞定了。现在虽然步骤多了,但他理解了每一步在做什么——"Vercel 帮我做的事情,我现在自己也能做了。而且有 Claude Code 帮忙写配置,也没那么难。"
应用部署完成了,但现在只能通过 IP 访问,不够专业。接下来配置域名和 HTTPS——14.4 配置域名与证书。