Coze 上线实战:从后端网关到 Docker 部署的完整方案
Coze 生产环境部署指南|附源码
本文面向准备将 Coze 应用 / Coze Bot / Coze 工作流能力接入真实业务系统的开发者,介绍一套相对完整的生产环境部署方案。内容包括整体架构设计、环境准备、后端服务封装、Docker 部署、Nginx 反向代理、HTTPS 配置、日志与监控、安全加固、CI/CD 自动发布,以及可直接参考的源码示例。
一、前言
Coze 是一类面向智能体、工作流、插件调用和大模型应用编排的平台。很多团队在开发阶段,通常会直接在 Coze 控制台完成 Bot 配置,然后通过 API 或 SDK 在业务系统中调用。
在测试环境中,这种方式足够快速;但一旦进入生产环境,就需要考虑更多工程化问题,例如:
- API Token 如何安全保存?
- 多个业务系统如何统一调用 Coze?
- 如何做限流、鉴权和审计?
- 如何处理接口失败、超时和重试?
- 如何记录用户会话与调用日志?
- 如何部署后端代理服务?
- 如何通过 Docker 或 Kubernetes 实现稳定发布?
- 如何配置 HTTPS、Nginx、监控和告警?
- 如何避免直接把 Coze Token 暴露给前端?
本文将提供一套推荐的生产部署方案:前端不直接调用 Coze,而是通过自建后端网关服务统一代理 Coze API。
这样可以更好地实现安全控制、调用治理、日志留存和后续扩展。
二、生产环境推荐架构
推荐架构如下:
用户浏览器 / App / 小程序
|
| HTTPS
v
Nginx / Ingress
|
v
业务后端服务 / Coze Gateway
|
| 调用 Coze API
v
Coze 平台 / 大模型服务
|
v
返回结果
如果系统规模较大,可以进一步扩展为:
Client
|
v
CDN
|
v
Nginx / API Gateway
|
+------------------+
| |
v v
Auth Service Coze Gateway
|
+--> Redis:会话缓存、限流
|
+--> MySQL/PostgreSQL:业务数据、调用日志
|
+--> Prometheus:监控指标
|
+--> Coze API
这种架构的优势包括:
-
保护密钥
Coze Token 只保存在服务端环境变量或密钥管理系统中,避免暴露给浏览器。 -
统一鉴权
业务用户需要先通过你自己的登录系统鉴权,然后才能调用智能体能力。 -
方便限流
可以按用户、IP、Bot、接口维度做限流,防止恶意调用导致成本失控。 -
便于审计
每一次对话请求、响应时间、消耗、错误信息都可以记录,便于后续排查问题。 -
支持灰度和多环境
开发、测试、预发、生产环境可以分别配置不同的 Bot ID 和 Token。
三、环境准备
本文以以下技术栈为例:
| 组件 | 版本建议 | 用途 |
|---|---|---|
| Node.js | 18+ / 20+ | 后端服务运行环境 |
| TypeScript | 5.x | 类型约束 |
| Express | 4.x | HTTP 服务 |
| Axios | 最新稳定版 | 调用 Coze API |
| Redis | 6+ | 缓存、限流 |
| PostgreSQL / MySQL | 8+ | 存储会话、日志 |
| Docker | 24+ | 容器化部署 |
| Nginx | 1.22+ | 反向代理、HTTPS |
| PM2 | 可选 | 非容器部署时进程管理 |
| GitHub Actions / GitLab CI | 可选 | 自动化部署 |
你需要提前准备:
- 一台 Linux 服务器,推荐 Ubuntu 22.04 LTS;
- 一个域名,例如
api.example.com; - 已完成备案和 DNS 解析;
- Coze 平台创建好的 Bot 或工作流;
- Coze API Token;
- SSL 证书,可以使用 Let’s Encrypt 免费证书;
- Docker 与 Docker Compose。
四、项目目录结构
下面是一套适合中小型项目的目录结构:
coze-gateway/
├── src/
│ ├── config/
│ │ └── env.ts
│ ├── controllers/
│ │ └── chat.controller.ts
│ ├── middlewares/
│ │ ├── auth.middleware.ts
│ │ ├── error.middleware.ts
│ │ └── rate-limit.middleware.ts
│ ├── services/
│ │ └── coze.service.ts
│ ├── utils/
│ │ └── logger.ts
│ └── app.ts
├── .env.example
├── Dockerfile
├── docker-compose.yml
├── nginx/
│ └── coze-gateway.conf
├── package.json
└── tsconfig.json
这套结构的设计原则是:
controller只处理 HTTP 请求和响应;service专门封装 Coze 调用逻辑;middleware负责鉴权、限流、异常处理;config统一读取环境变量;- 生产环境不把任何 Token 写死在代码里。
五、后端服务源码示例
下面给出一个基于 Node.js + Express + TypeScript 的生产可用基础版本。
1. package.json
{
"name": "coze-gateway",
"version": "1.0.0",
"description": "Production gateway service for Coze API",
"main": "dist/app.js",
"scripts": {
"dev": "ts-node-dev --respawn --transpile-only src/app.ts",
"build": "tsc",
"start": "node dist/app.js"
},
"dependencies": {
"axios": "^1.7.0",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.18.3",
"helmet": "^7.1.0",
"morgan": "^1.10.0",
"express-rate-limit": "^7.2.0"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/morgan": "^1.9.9",
"ts-node-dev": "^2.0.0",
"typescript": "^5.4.0"
}
}
2. .env.example
NODE_ENV=production
PORT=3000
# Coze 配置
COZE_API_BASE_URL=https://api.coze.cn
COZE_API_TOKEN=your_coze_api_token
COZE_BOT_ID=your_bot_id
# 业务鉴权
APP_API_KEY=your_internal_api_key
# CORS
CORS_ORIGIN=https://www.example.com
生产环境中不要直接提交 .env 文件到 Git 仓库,建议使用服务器环境变量、Docker Secret、Kubernetes Secret 或云厂商密钥管理服务。
3. 环境变量配置:src/config/env.ts
import dotenv from "dotenv";
dotenv.config();
function required(name: string): string {
const value = process.env[name];
if (!value) {
throw new Error(`Missing required environment variable: ${name}`);
}
return value;
}
export const env = {
nodeEnv: process.env.NODE_ENV || "development",
port: Number(process.env.PORT || 3000),
coze: {
apiBaseUrl: required("COZE_API_BASE_URL"),
apiToken: required("COZE_API_TOKEN"),
botId: required("COZE_BOT_ID")
},
app: {
apiKey: required("APP_API_KEY")
},
corsOrigin: process.env.CORS_ORIGIN || "*"
};
4. Coze 调用服务:src/services/coze.service.ts
注意:不同地区、不同版本的 Coze API 路径和参数可能有所差异,请以你所使用平台的官方 API 文档为准。下面代码展示的是一种通用封装思路。
import axios from "axios";
import { env } from "../config/env";
export interface ChatMessage {
role: "user" | "assistant" | "system";
content: string;
}
export interface ChatRequest {
userId: string;
conversationId?: string;
message: string;
}
export interface ChatResponse {
conversationId?: string;
reply: string;
raw?: unknown;
}
export class CozeService {
private client = axios.create({
baseURL: env.coze.apiBaseUrl,
timeout: 30000,
headers: {
Authorization: `Bearer ${env.coze.apiToken}`,
"Content-Type": "application/json"
}
});
async chat(payload: ChatRequest): Promise {
try {
const response = await this.client.post("/v3/chat", {
bot_id: env.coze.botId,
user_id: payload.userId,
conversation_id: payload.conversationId,
additional_messages: [
{
role: "user",
content: payload.message,
content_type: "text"
}
],
stream: false
});
return this.normalizeResponse(response.data);
} catch (error: any) {
const status = error?.response?.status;
const data = error?.response?.data;
console.error("Coze API error:", {
status,
data,
message: error.message
});
throw new Error("Coze service unavailable");
}
}
private normalizeResponse(data: any): ChatResponse {
/**
* 实际生产中需要根据 Coze API 的真实响应结构做解析。
* 这里提供一个兜底示例。
*/
let reply = "";
if (data?.messages && Array.isArray(data.messages)) {
const assistantMessage = data.messages.find(
(item: any) => item.role === "assistant"
);
reply = assistantMessage?.content || "";
}
if (!reply && data?.data?.answer) {
reply = data.data.answer;
}
if (!reply) {
reply = "抱歉,我暂时无法回答这个问题。";
}
return {
conversationId: data?.conversation_id || data?.data?.conversation_id,
reply,
raw: data
};
}
}
export const cozeService = new CozeService();
5. 鉴权中间件:src/middlewares/auth.middleware.ts
import { Request, Response, NextFunction } from "express";
import { env } from "../config/env";
export function authMiddleware(
req: Request,
res: Response,
next: NextFunction
) {
const apiKey = req.headers["x-api-key"];
if (!apiKey || apiKey !== env.app.apiKey) {
return res.status(401).json({
code: 401,
message: "Unauthorized"
});
}
next();
}
生产环境中,x-api-key 只是最简单的方式。真正面向用户的系统建议使用:
- JWT;
- OAuth2;
- Session;
- 企业 SSO;
- 服务端签名;
- 网关级鉴权。
6. 限流中间件:src/middlewares/rate-limit.middleware.ts
import rateLimit from "express-rate-limit";
export const rateLimitMiddleware = rateLimit({
windowMs: 60 * 1000,
limit: 60,
standardHeaders: true,
legacyHeaders: false,
message: {
code: 429,
message: "Too many requests, please try again later."
}
});
这个示例表示同一个 IP 每分钟最多请求 60 次。实际生产环境建议接入 Redis 做分布式限流,避免多实例部署时限流不准确。
7. 控制器:src/controllers/chat.controller.ts
import { Request, Response, NextFunction } from "express";
import { cozeService } from "../services/coze.service";
export async function chatController(
req: Request,
res: Response,
next: NextFunction
) {
try {
const { userId, conversationId, message } = req.body;
if (!userId || !message) {
return res.status(400).json({
code: 400,
message: "userId and message are required"
});
}
if (typeof message !== "string" || message.length > 2000) {
return res.status(400).json({
code: 400,
message: "message is invalid"
});
}
const result = await cozeService.chat({
userId,
conversationId,
message
});
return res.json({
code: 0,
data: result
});
} catch (error) {
next(error);
}
}
8. 全局异常处理:src/middlewares/error.middleware.ts
import { Request, Response, NextFunction } from "express";
export function errorMiddleware(
error: Error,
req: Request,
res: Response,
next: NextFunction
) {
console.error("Unhandled error:", {
path: req.path,
method: req.method,
message: error.message,
stack: error.stack
});
res.status(500).json({
code: 500,
message: "Internal server error"
});
}
9. 应用入口:src/app.ts
import express from "express";
import cors from "cors";
import helmet from "helmet";
import morgan from "morgan";
import { env } from "./config/env";
import { authMiddleware } from "./middlewares/auth.middleware";
import { rateLimitMiddleware } from "./middlewares/rate-limit.middleware";
import { errorMiddleware } from "./middlewares/error.middleware";
import { chatController } from "./controllers/chat.controller";
const app = express();
app.use(helmet());
app.use(cors({ origin: env.corsOrigin }));
app.use(express.json({ limit: "1mb" }));
app.use(morgan("combined"));
app.get("/health", (req, res) => {
res.json({
status: "ok",
env: env.nodeEnv,
timestamp: Date.now()
});
});
app.post(
"/api/coze/chat",
authMiddleware,
rateLimitMiddleware,
chatController
);
app.use(errorMiddleware);
app.listen(env.port, () => {
console.log(`Coze Gateway is running on port ${env.port}`);
});
六、本地运行测试
安装依赖:
npm install
复制环境变量文件:
cp .env.example .env
修改 .env:
COZE_API_TOKEN=真实的 Coze Token
COZE_BOT_ID=真实的 Bot ID
APP_API_KEY=自定义调用密钥
启动开发服务:
npm run dev
测试健康检查:
curl http://localhost:3000/health
测试聊天接口:
curl -X POST http://localhost:3000/api/coze/chat \
-H "Content-Type: application/json" \
-H "x-api-key: your_internal_api_key" \
-d '{
"userId": "user_10001",
"message": "你好,请介绍一下你自己"
}'
如果返回类似以下结果,说明服务基本可用:
{
"code": 0,
"data": {
"conversationId": "xxx",
"reply": "你好,我是你的智能助手,可以帮助你解答问题、处理任务和生成内容。"
}
}
七、Docker 化部署
生产环境更推荐使用 Docker 部署,便于迁移、扩容和回滚。
1. Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src ./src
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/app.js"]
2. docker-compose.yml
version: "3.9"
services:
coze-gateway:
build:
context: .
dockerfile: Dockerfile
container_name: coze-gateway
restart: always
ports:
- "3000:3000"
environment:
NODE_ENV: production
PORT: 3000
COZE_API_BASE_URL: https://api.coze.cn
COZE_API_TOKEN: ${COZE_API_TOKEN}
COZE_BOT_ID: ${COZE_BOT_ID}
APP_API_KEY: ${APP_API_KEY}
CORS_ORIGIN: https://www.example.com
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
3. 构建并启动
docker compose up -d --build
查看容器:
docker ps
查看日志:
docker logs -f coze-gateway
停止服务:
docker compose down
八、Nginx 反向代理配置
生产环境中不建议直接暴露 Node.js 服务端口,推荐使用 Nginx 作为入口。
nginx/coze-gateway.conf
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
将配置软链接到 Nginx:
sudo ln -s /path/to/coze-gateway/nginx/coze-gateway.conf /etc/nginx/sites-enabled/coze-gateway.conf
检查配置:
sudo nginx -t
重载 Nginx:
sudo systemctl reload nginx
九、HTTPS 配置
推荐使用 Certbot 自动签发 Let’s Encrypt 证书。
安装 Certbot:
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
签发证书:
sudo certbot --nginx -d api.example.com
签发完成后,Certbot 会自动修改 Nginx 配置,增加 HTTPS 监听。
你也可以手动配置:
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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 https;
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}
十、生产环境安全建议
1. 不要在前端暴露 Coze Token
这是最重要的一条。任何写在前端代码里的 Token,都可以被用户通过浏览器开发者工具、抓包工具或反编译方式获取。
正确做法是:
前端 -> 你的后端 -> Coze API
错误做法是:
前端 -> Coze API
2. 做好请求鉴权
至少要保证接口不是裸奔的。可以选择:
- 用户登录态;
- JWT;
- App Key + 签名;
- 服务端 Session;
- OAuth2;
- 内部网关鉴权。
3. 控制请求长度
大模型接口通常按调用量、Token 或上下文长度计费。如果不限制输入长度,可能被恶意刷接口。
建议:
- 单条消息限制在 1000~4000 字符;
- 文件上传单独做大小限制;
- 对同一用户做频率限制;
- 对异常请求做黑名单策略。
4. 日志脱敏
不要在日志中完整记录:
- 用户手机号;
- 身份证;
- 邮箱;
- 地址;
- API Token;
- Cookie;
- Authorization Header。
可以在日志写入前做脱敏处理。
5. 配置超时和重试
调用 Coze API 时一定要配置超时时间。不要让请求无限等待。
推荐:
- 连接超时:5~10 秒;
- 总超时:30~60 秒;
- 对幂等请求可以做有限重试;
- 对聊天生成类接口,重试要谨慎,避免重复扣费或重复生成。
十一、日志与监控
生产环境至少需要关注以下指标:
| 指标 | 含义 |
|---|---|
| QPS | 每秒请求数 |
| P95/P99 延迟 | 接口响应耗时 |
| 错误率 | 4xx、5xx 占比 |
| Coze API 调用失败率 | 上游接口稳定性 |
| Token / 调用量消耗 | 成本控制 |
| 限流次数 | 是否存在异常访问 |
| 容器 CPU / 内存 | 服务资源占用 |
| 磁盘使用量 | 日志是否撑满磁盘 |
如果项目规模较小,可以先使用:
- Docker logs;
- Nginx access log;
- 云服务器监控;
- 简单的告警脚本。
如果进入正式商业化阶段,建议接入:
- Prometheus;
- Grafana;
- Loki;
- ELK;
- OpenTelemetry;
- Sentry。
十二、数据库表设计建议
如果你需要记录用户会话,可以设计如下表。
1. 会话表
CREATE TABLE coze_conversations (
id BIGSERIAL PRIMARY KEY,
user_id VARCHAR(128) NOT NULL,
conversation_id VARCHAR(128),
title VARCHAR(255),
status VARCHAR(32) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_coze_conversations_user_id
ON coze_conversations(user_id);
2. 消息表
CREATE TABLE coze_messages (
id BIGSERIAL PRIMARY KEY,
conversation_id VARCHAR(128),
user_id VARCHAR(128) NOT NULL,
role VARCHAR(32) NOT NULL,
content TEXT NOT NULL,
request_id VARCHAR(128),
latency_ms INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_coze_messages_conversation_id
ON coze_messages(conversation_id);
3. 调用日志表
CREATE TABLE coze_call_logs (
id BIGSERIAL PRIMARY KEY,
user_id VARCHAR(128),
bot_id VARCHAR(128),
endpoint VARCHAR(255),
status_code INT,
success BOOLEAN DEFAULT false,
error_message TEXT,
latency_ms INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_coze_call_logs_created_at
ON coze_call_logs(created_at);
这些表不一定一开始全部使用,但建议至少保留调用日志,方便定位线上问题。
十三、CI/CD 自动化部署示例
以下是 GitHub Actions 示例。思路是:提交到 main 分支后,自动连接服务器,拉取代码并重启 Docker Compose。
.github/workflows/deploy.yml
name: Deploy Coze Gateway
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Deploy to server
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /data/apps/coze-gateway
git pull origin main
docker compose down
docker compose up -d --build
docker image prune -f
需要在 GitHub 仓库中配置以下 Secrets:
SERVER_HOSTSERVER_USERSERVER_SSH_KEY
生产环境建议进一步优化为:
- 构建镜像并推送到镜像仓库;
- 服务器只拉取固定版本镜像;
- 支持蓝绿部署;
- 支持失败自动回滚;
- 加入数据库迁移流程。
十四、常见问题排查
1. 接口返回 401
可能原因:
COZE_API_TOKEN配置错误;- Token 过期或权限不足;
- 请求头 Authorization 格式错误;
- 调用了错误区域的 API 域名。
排查方式:
docker exec -it coze-gateway sh
printenv | grep COZE
确认环境变量是否正确注入。
2. Nginx 返回 502
可能原因:
- Node 服务没有启动;
- Docker 容器异常退出;
- Nginx
proxy_pass地址错误; - 防火墙或端口未开放。
排查命令:
docker ps
docker logs -f coze-gateway
curl http://127.0.0.1:3000/health
sudo nginx -t
3. 请求超时
可能原因:
- Coze API 响应较慢;
- 服务器网络访问 Coze 不稳定;
- Nginx
proxy_read_timeout太短; - 后端 Axios timeout 太短;
- 大模型生成内容过长。
可以适当调大:
proxy_read_timeout 120s;
同时在后端根据业务场景调整:
timeout: 60000
4. 生产环境跨域失败
检查后端配置:
app.use(cors({ origin: env.corsOrigin }));
确认 .env 中:
CORS_ORIGIN=https://www.example.com
如果有多个域名,可以改为白名单逻辑,而不是直接使用 *。
十五、上线前检查清单
上线前建议逐项确认:
- [ ] Coze Token 未写入前端代码;
- [ ] 生产环境
.env未提交到 Git; - [ ] 已开启 HTTPS;
- [ ] Nginx 反向代理配置正确;
- [ ]
/health健康检查正常; - [ ] 接口已接入鉴权;
- [ ] 已设置请求频率限制;
- [ ] 已限制用户输入长度;
- [ ] 已配置超时时间;
- [ ] 已记录错误日志;
- [ ] 已准备回滚方案;
- [ ] 已设置服务器监控;
- [ ] 已配置日志轮转;
- [ ] 已验证容器重启策略;
- [ ] 已完成压力测试;
- [ ] 已检查 Coze 调用额度和计费策略。
十六、总结
将 Coze 能力接入生产环境,并不只是简单调用一个 API。真正稳定的线上系统,需要在安全、鉴权、限流、日志、监控、容器化、自动部署和故障恢复等方面做好工程化设计。
本文给出了一套相对通用的方案:
- 使用后端网关服务代理 Coze API;
- 通过环境变量管理 Token;
- 使用 Express 封装统一接口;
- 使用 Docker 和 Docker Compose 部署;
- 使用 Nginx 提供反向代理和 HTTPS;
- 增加鉴权、限流、日志和异常处理;
- 使用 CI/CD 实现自动化发布;
- 通过数据库记录会话和调用日志。
如果你的业务仍处于验证阶段,可以先使用本文中的轻量版本快速上线;如果你的业务已经进入规模化阶段,则建议进一步引入 Redis 分布式限流、消息队列、Kubernetes、可观测性平台和密钥管理系统。
最终目标是:既能快速使用 Coze 的智能体能力,又能保证生产环境的安全、稳定、可维护和可扩展。