部署指南
将 Sistine Starter 部署到生产环境的完整指南
部署指南
本指南将帮助你将 Sistine Starter 部署到生产环境,包括数据库配置、环境变量设置、Webhook 配置和定时任务设置。
部署清单
在开始部署前,请确保完成以下准备工作:
1. 环境准备
- PostgreSQL 数据库: Neon
- 火山引擎 API Key: 申请地址
- Creem 账号和 API Key: 注册地址
- Resend API Key: 注册地址
- Google OAuth 凭据 (可选): Google Cloud Console
- S3 存储配置 (可选): AWS S3 或兼容服务
- 域名 (生产环境): 已备案的域名
2. 账号注册
服务 | 用途 | 免费额度 | 注册链接 |
---|---|---|---|
Vercel | 应用托管 | 100GB 带宽/月 | vercel.com |
Neon | PostgreSQL 数据库 | 500MB 存储 + 100小时计算 | neon.tech |
火山引擎 | AI 服务 | 试用额度 | volcengine.com |
Creem | 支付网关 | 测试模式免费 | creem.io |
Resend | 邮件服务 | 100 封/天 | resend.com |
PostHog (可选) | 分析工具 | 1M 事件/月 | posthog.com |
数据库迁移步骤
步骤 1: 创建生产数据库
使用 Neon (推荐)
- 访问 neon.tech 并登录
- 点击 Create Project
- 配置项目:
- Project name:
sistine-production
- Region: 选择离目标用户最近的区域
- PostgreSQL version: 选择最新稳定版 (16+)
- Project name:
- 创建完成后,复制连接字符串 (包含
?sslmode=require
)
示例连接字符串:
postgresql://username:password@ep-xxx.us-east-2.aws.neon.tech/main?sslmode=require
步骤 2: 执行数据库迁移
在本地执行迁移,将 Schema 应用到生产数据库:
# 1. 设置生产数据库 URL
export DATABASE_URL="postgresql://user:password@host/db?sslmode=require"
# 2. 执行迁移
pnpm db:migrate
# 3. 验证迁移
pnpm db:studio
重要提示:
- ✅ 生产环境推荐使用 迁移文件 (
db:migrate
) - ✅ 确保
.env.local
中的DATABASE_URL
不会被提交到 Git - ✅ 执行迁移前先备份数据库 (如果已有数据)
步骤 3: 验证表结构
使用 Drizzle Studio 或 Neon 的 GUI 验证以下表已创建:
核心表:
user
(用户表)session
(会话表)account
(账户表)payment
(支付记录表)subscription
(订阅表)creditLedger
(积分账本表)subscriptionCreditSchedule
(订阅积分调度表)
AI 功能表:
chatSession
(对话会话表)chatMessage
(对话消息表)generationHistory
(生成历史表)
其他表:
passwordResetToken
(密码重置表)newsletterSubscription
(Newsletter 订阅表)
Vercel 部署指南 (推荐)
Vercel 是部署 Next.js 应用的最佳平台,提供零配置部署、自动 HTTPS、全球 CDN 和边缘函数支持。
步骤 1: 连接 Git 仓库
- 推送代码到 Git:
# 如果尚未初始化 Git
git init
git add .
git commit -m "Initial commit"
# 推送到 GitHub
git remote add origin https://github.com/your-username/your-repo.git
git push -u origin main
-
登录 Vercel:
- 访问 vercel.com
- 使用 GitHub 账号登录
-
导入项目:
- 点击 Add New > Project
- 选择你的 GitHub 仓库
- 点击 Import
步骤 2: 配置环境变量
在 Vercel 项目设置中添加环境变量:
路径: Project Settings > Environment Variables
必需的环境变量
# 数据库
DATABASE_URL="postgresql://user:password@host/db?sslmode=require"
# Better Auth
BETTER_AUTH_SECRET="至少32字符的随机密钥"
BETTER_AUTH_URL="https://yourdomain.com" # 使用实际域名
BETTER_AUTH_TRUSTED_ORIGINS="https://yourdomain.com,https://preview.yourdomain.com"
# 火山引擎 (AI 服务)
VOLCANO_ENGINE_API_KEY="your-volcano-engine-api-key"
VOLCANO_ENGINE_API_URL="https://ark.cn-beijing.volces.com/api/v3"
# Creem 支付
CREEM_API_KEY="your-creem-api-key"
CREEM_WEBHOOK_SECRET="whsec_your_webhook_secret"
# Resend 邮件
RESEND_API_KEY="re_your_api_key"
RESEND_FROM_EMAIL="Your App <noreply@yourdomain.com>"
# 定时任务认证
CRON_SECRET="生成一个随机密钥"
# 应用 URL
NEXT_PUBLIC_APP_URL="https://yourdomain.com"
可选的环境变量
# Google OAuth (如果启用)
AUTH_GOOGLE_ID="your-google-client-id"
AUTH_GOOGLE_SECRET="your-google-client-secret"
# 分析工具
NEXT_PUBLIC_POSTHOG_KEY="phc_your_posthog_key"
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID="G-XXXXXXXXXX"
NEXT_PUBLIC_CLARITY_PROJECT_ID="your_clarity_id"
# S3 存储 (如果使用)
STORAGE_ENDPOINT="https://s3.amazonaws.com"
STORAGE_BUCKET="your-bucket-name"
STORAGE_ACCESS_KEY_ID="your-access-key"
STORAGE_SECRET_ACCESS_KEY="your-secret-key"
STORAGE_REGION="us-east-1"
生成随机密钥:
# 方法 1: OpenSSL
openssl rand -base64 32
# 方法 2: Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
环境变量分组建议:
环境 | 说明 |
---|---|
Production | 生产环境变量 (使用真实 API Key 和域名) |
Preview | 预览环境变量 (可使用测试 API Key) |
Development | 开发环境变量 (本地开发使用) |
步骤 3: 构建设置
Vercel 会自动检测 Next.js 项目,以下是默认配置:
Build Command: pnpm build
(自动检测)
Output Directory: .next
(自动检测)
Install Command: pnpm install
(自动检测)
Node.js Version: 20.x (推荐)
如需自定义,在项目根目录创建 vercel.json
:
{
"buildCommand": "pnpm build",
"devCommand": "pnpm dev",
"installCommand": "pnpm install",
"framework": "nextjs",
"regions": ["iad1"],
"functions": {
"app/api/**/*.ts": {
"maxDuration": 60
}
}
}
配置说明:
regions
: 部署区域 (如iad1
= 美国东部,hnd1
= 日本东京)maxDuration
: API 路由最大执行时间 (Pro 计划可设置 60s+)
步骤 4: 域名配置
使用 Vercel 默认域名
部署完成后,Vercel 会自动分配域名:
https://your-project.vercel.app
绑定自定义域名
-
添加域名:
- 进入 Project Settings > Domains
- 输入你的域名 (如
yourdomain.com
) - 点击 Add
-
配置 DNS: 在你的域名服务商 (如 Cloudflare、阿里云、腾讯云) 添加 DNS 记录:
方法 A: CNAME (推荐)
类型: CNAME 名称: @ (或 www) 值: cname.vercel-dns.com
方法 B: A 记录
类型: A 名称: @ 值: 76.76.21.21
-
验证域名:
- DNS 生效后,Vercel 会自动验证并签发 SSL 证书
- 通常需要 5-10 分钟
-
更新环境变量: 将
BETTER_AUTH_URL
和NEXT_PUBLIC_APP_URL
更新为自定义域名:BETTER_AUTH_URL="https://yourdomain.com" NEXT_PUBLIC_APP_URL="https://yourdomain.com"
步骤 5: 首次部署
-
点击 Deploy: Vercel 会自动构建和部署应用
-
查看部署日志: 监控构建过程,确保没有错误
-
访问应用: 部署成功后,访问分配的域名验证应用是否正常运行
常见部署错误:
- 构建失败: 检查环境变量是否正确设置
- 数据库连接错误: 确认
DATABASE_URL
是否正确 - API 调用失败: 检查 API Key 是否有效
配置 Creem Webhook
Webhook 用于接收支付事件通知,是订阅和支付系统正常工作的关键。
步骤 1: 在 Creem Dashboard 中设置
-
登录 Creem Dashboard: creem.io/dashboard
-
进入 Developers > Webhooks:
- 点击左侧菜单的 Developers
- 选择 Webhooks
-
添加 Endpoint:
- 点击 Add endpoint
- Endpoint URL:
https://yourdomain.com/api/payments/creem/webhook
- Description:
Production Webhook
-
选择事件: 勾选以下事件 (或选择 Select all events):
checkout.completed
- 支付完成subscription.paid
- 订阅续费成功subscription.active
- 订阅激活subscription.canceled
- 订阅取消subscription.expired
- 订阅过期
-
获取 Signing Secret:
- 保存后,复制 Signing Secret (格式:
whsec_...
) - 将其添加到 Vercel 环境变量
CREEM_WEBHOOK_SECRET
- 保存后,复制 Signing Secret (格式:
步骤 2: 测试 Webhook
方法 1: 使用 Creem CLI
# 安装 Creem CLI
npm install -g @creem/cli
# 登录
creem login
# 转发 webhook 到本地 (用于开发测试)
creem listen --forward-to localhost:3000/api/payments/creem/webhook
方法 2: 发送测试事件
在 Creem Dashboard 的 Webhook 页面:
- 点击刚创建的 Webhook
- 点击 Send test webhook
- 选择事件类型 (如
checkout.completed
) - 点击 Send test event
方法 3: 真实测试支付
- 在 Creem 中启用 Test Mode
- 访问你的应用定价页
- 使用测试卡号完成支付:
卡号: 4242 4242 4242 4242 过期日期: 任意未来日期 CVC: 任意 3 位数字
- 检查 Webhook 是否触发并正确处理
步骤 3: 验证 Webhook 签名
Webhook 签名验证在 app/api/payments/creem/webhook/route.ts
中自动处理:
import { verifyWebhookSignature } from '@/lib/payments/creem';
const signature = request.headers.get('creem-signature');
const rawBody = await request.text();
const isValid = verifyWebhookSignature(rawBody, signature, webhookSecret);
if (!isValid) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
}
安全提示:
- ✅ 始终验证 Webhook 签名
- ✅ 使用 HTTPS (Vercel 自动提供)
- ✅ 不要在日志中打印敏感信息
步骤 4: 监控 Webhook 事件
在 Creem Dashboard 中查看 Webhook 日志:
- 进入 Developers > Webhooks
- 点击你的 Webhook
- 查看 Recent deliveries
状态码说明:
200
: 成功处理401
: 签名验证失败500
: 服务器错误
配置定时任务 (Vercel Cron Jobs)
定时任务用于自动发放年付订阅的分期积分。
步骤 1: 配置 Cron 端点
在 vercel.json
中添加 Cron 配置:
{
"crons": [
{
"path": "/api/cron/grant-subscription-credits",
"schedule": "0 * * * *"
}
]
}
Schedule 语法 (Cron 表达式):
分 时 日 月 周
0 * * * * → 每小时整点执行
0 0 * * * → 每天午夜执行
0 */6 * * * → 每 6 小时执行
常用 Schedule:
表达式 | 说明 |
---|---|
0 * * * * | 每小时整点 (推荐) |
0 0 * * * | 每天午夜 |
0 */6 * * * | 每 6 小时 |
0 0 1 * * | 每月 1 号午夜 |
步骤 2: Cron 端点认证
Cron 端点需要认证以防止未授权访问:
方法 1: 使用 Vercel Cron Secret (推荐)
Vercel 自动在 Cron 请求中添加 authorization
头:
// app/api/cron/grant-subscription-credits/route.ts
export async function GET(request: NextRequest) {
// 验证 Vercel Cron Secret
const authHeader = request.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// 执行积分发放逻辑
// ...
}
在 Vercel 环境变量中设置:
CRON_SECRET="生成一个随机密钥"
方法 2: 使用 Vercel 内部验证
import { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
// 验证请求来自 Vercel Cron
const cronSecret = request.headers.get('x-vercel-cron-secret');
if (cronSecret !== process.env.CRON_SECRET) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// ...
}
步骤 3: 测试定时任务
本地测试
使用 cURL 手动触发:
curl -X GET \
http://localhost:3000/api/cron/grant-subscription-credits \
-H "Authorization: Bearer YOUR_CRON_SECRET"
生产环境测试
在 Vercel Dashboard 中:
- 进入 Project > Cron Jobs
- 找到你的 Cron Job
- 点击 Run now 手动触发
步骤 4: 监控 Cron 执行
查看 Cron 执行日志:
- 进入 Vercel Dashboard > Project > Deployments
- 点击 Functions
- 找到
/api/cron/grant-subscription-credits
- 查看执行日志和错误信息
调试提示:
- 在 Cron 函数中添加详细日志
- 使用
console.log
输出执行状态 - 检查函数执行时间 (避免超时)
创建管理员账户
部署完成后,创建第一个管理员账户以访问管理后台。
方法 1: 使用命令行工具 (推荐)
- 克隆仓库到本地 (如果尚未克隆):
git clone https://github.com/your-username/your-repo.git
cd your-repo
- 设置生产数据库 URL:
export DATABASE_URL="postgresql://user:password@host/db?sslmode=require"
- 运行管理员设置脚本:
pnpm admin:setup
- 按提示输入信息:
Enter admin email: admin@yourdomain.com
Enter admin password: ********
Enter admin name: Admin User
- 验证管理员账户:
- 访问
https://yourdomain.com/zh/login
- 使用刚创建的邮箱和密码登录
- 访问
https://yourdomain.com/zh/admin
确认能访问管理后台
- 访问
方法 2: 手动在数据库中创建
如果没有命令行工具访问权限,可以手动在数据库中设置:
-
登录数据库管理界面 (Neon / Supabase GUI 或 Drizzle Studio)
-
找到你的用户记录:
SELECT id, email, role FROM "user" WHERE email = 'your-email@example.com';
- 更新 role 为 admin:
UPDATE "user"
SET role = 'admin'
WHERE email = 'your-email@example.com';
- 验证更新:
SELECT id, email, role FROM "user" WHERE email = 'your-email@example.com';
应该看到 role
列显示为 admin
。
环境变量检查
部署前,确保以下环境变量使用正确的值:
生产环境必须修改的变量
环境变量 | 开发环境 | 生产环境 |
---|---|---|
BETTER_AUTH_URL | http://localhost:3000 | https://yourdomain.com |
NEXT_PUBLIC_APP_URL | http://localhost:3000 | https://yourdomain.com |
RESEND_FROM_EMAIL | noreply@localhost | Your App <noreply@yourdomain.com> |
DATABASE_URL | 本地数据库 | 生产数据库 |
BETTER_AUTH_SECRET | 测试密钥 | 强随机密钥 (32+ 字符) |
验证脚本
创建 .env.production
文件检查:
#!/bin/bash
echo "Checking production environment variables..."
# 必需变量列表
REQUIRED_VARS=(
"DATABASE_URL"
"BETTER_AUTH_SECRET"
"BETTER_AUTH_URL"
"VOLCANO_ENGINE_API_KEY"
"CREEM_API_KEY"
"CREEM_WEBHOOK_SECRET"
"RESEND_API_KEY"
"RESEND_FROM_EMAIL"
"CRON_SECRET"
"NEXT_PUBLIC_APP_URL"
)
# 检查每个变量
for var in "${REQUIRED_VARS[@]}"; do
if [ -z "${!var}" ]; then
echo "❌ Missing: $var"
else
echo "✅ Set: $var"
fi
done
生产环境优化建议
1. 性能优化
启用 Next.js 静态优化
在 next.config.mjs
中:
/** @type {import('next').NextConfig} */
const nextConfig = {
// 启用静态导出 (部分页面)
output: 'standalone',
// 图片优化
images: {
domains: ['yourdomain.com'],
formats: ['image/avif', 'image/webp'],
},
// 压缩
compress: true,
// React 严格模式
reactStrictMode: true,
// 生产环境禁用 source map
productionBrowserSourceMaps: false,
};
export default nextConfig;
使用 CDN 加速静态资源
Vercel 自动提供全球 CDN,无需额外配置。
数据库连接池
使用 Neon 的连接池模式:
# Neon 自动使用连接池
DATABASE_URL="postgresql://user:pass@ep-xxx.pooler.us-east-2.aws.neon.tech/main"
2. 安全优化
设置安全响应头
在 next.config.mjs
中:
const nextConfig = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'X-Frame-Options',
value: 'DENY',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
],
},
];
},
};
限制 API 速率 (Rate Limiting)
安装并配置速率限制中间件:
pnpm add @upstash/ratelimit @upstash/redis
// lib/rate-limit.ts
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
export const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '1 m'), // 10 次/分钟
});
在 API 路由中使用:
import { ratelimit } from '@/lib/rate-limit';
export async function POST(request: NextRequest) {
const identifier = request.ip ?? 'anonymous';
const { success } = await ratelimit.limit(identifier);
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429 }
);
}
// 处理请求
}
定期轮换密钥
每 3-6 个月更换以下密钥:
BETTER_AUTH_SECRET
CRON_SECRET
CREEM_WEBHOOK_SECRET
3. 监控和日志
使用 Vercel Analytics
在 app/[locale]/layout.tsx
中添加:
import { Analytics } from '@vercel/analytics/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
);
}
集成错误追踪 (Sentry)
pnpm add @sentry/nextjs
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1,
});
数据库监控
在 Neon Dashboard 中监控:
- 查询性能
- 连接数
- 存储使用量
- 慢查询日志
4. 备份策略
数据库自动备份
Neon:
- 自动每日备份 (保留 7 天)
- 手动创建快照: Project > Backups > Create snapshot
# 手动备份
pg_dump "postgresql://user:pass@host/db" > backup-$(date +%Y%m%d).sql
# 恢复备份
psql "postgresql://user:pass@host/db" < backup-20251015.sql
代码备份
确保代码推送到 Git 远程仓库:
git push origin main
5. 扩展性优化
边缘函数 (Edge Functions)
将轻量级 API 迁移到边缘函数以降低延迟:
// app/api/hello/route.ts
export const runtime = 'edge'; // 启用边缘运行时
export async function GET() {
return new Response('Hello from Edge!');
}
数据库分区 (针对大规模应用)
对大表进行分区 (如 creditLedger
, chatMessage
):
例如按月份为 creditLedger
创建分区,具体 SQL 迁移可参考 数据库
文档或你自己的迁移脚本。
缓存策略
使用 Redis 缓存热点数据:
import { Redis } from '@upstash/redis';
const redis = Redis.fromEnv();
// 缓存用户积分
export async function getUserCredits(userId: string) {
const cached = await redis.get(`credits:${userId}`);
if (cached) return cached;
const credits = await db.query.user.findFirst({
where: eq(user.id, userId),
columns: { credits: true },
});
await redis.set(`credits:${userId}`, credits, { ex: 300 }); // 缓存 5 分钟
return credits;
}
常见部署问题
1. 构建失败: "Module not found"
原因: 依赖未正确安装
解决方法:
# 清理缓存并重新安装
rm -rf node_modules .next
pnpm install
pnpm build
2. 数据库连接超时
原因: 数据库 URL 错误或网络问题
解决方法:
- 检查
DATABASE_URL
是否正确 - 确认包含
?sslmode=require
- 检查数据库防火墙设置 (允许 Vercel IP)
3. Webhook 未触发
原因: Webhook URL 错误或签名验证失败
解决方法:
- 检查 Creem Dashboard 中的 Webhook URL
- 确认
CREEM_WEBHOOK_SECRET
与 Dashboard 一致 - 查看 Creem Webhook 日志中的错误信息
4. Cron Job 未执行
原因: Cron 配置错误或认证失败
解决方法:
- 检查
vercel.json
中的 Cron 配置 - 确认
CRON_SECRET
环境变量已设置 - 在 Vercel Dashboard 中手动触发测试
5. Google OAuth 重定向错误
原因: 回调 URL 未在 Google Console 中配置
解决方法:
- 在 Google Cloud Console 中添加生产环境回调 URL:
https://yourdomain.com/api/auth/callback/google
- 更新
BETTER_AUTH_URL
为生产域名
6. 邮件发送失败
原因: 域名未在 Resend 中验证
解决方法:
- 在 Resend Dashboard 中添加域名
- 配置 DNS 记录 (SPF, DKIM)
- 等待验证完成
- 更新
RESEND_FROM_EMAIL
使用已验证的域名
7. 页面 404 错误
原因: 动态路由配置问题
解决方法:
- 检查
middleware.ts
的 matcher 配置 - 确认
i18n.config.ts
中的 locale 设置 - 清除浏览器缓存并重试
部署后检查清单
部署完成后,逐一检查以下项目:
功能测试
- 首页加载正常: 访问
https://yourdomain.com
- 用户注册: 注册新账户,确认收到验证邮件
- 用户登录: 使用邮箱密码登录
- Google OAuth: 使用 Google 账号登录 (如果启用)
- 积分显示: 查看仪表板,确认新用户获得 300 积分
- 支付流程: 购买积分包或订阅,确认 Webhook 触发
- AI 功能: 测试对话、图像生成、视频生成
- 管理后台: 使用管理员账户访问
/zh/admin
- 语言切换: 切换中英文,确认翻译正确
- 响应式设计: 在移动设备上测试
安全检查
- HTTPS 启用: 所有页面使用 HTTPS
- 环境变量隔离: 不同环境使用不同的 API Key
- Webhook 签名验证: Webhook 端点验证签名
- Cron 认证: Cron 端点需要认证
- SQL 注入防护: 使用参数化查询
- CSRF 保护: Better Auth 自动提供
性能检查
- 首屏加载时间 < 3 秒
- Lighthouse 分数 > 90
- 图片优化: 使用 WebP/AVIF 格式
- CDN 缓存: 静态资源使用 CDN
- 数据库查询优化: 慢查询 < 100ms
监控设置
- 错误追踪: Sentry 或类似工具已配置
- 分析工具: PostHog / Google Analytics 已启用
- 日志监控: Vercel Logs 可查看运行日志
- 告警设置: 关键错误自动发送通知