部署 Server
将 Hono 服务端部署到 Cloudflare Workers,包含 D1、R2 和 Secrets 配置
部署 Server(Cloudflare Workers)
EasyStarter 的服务端基于 Hono,运行在 Cloudflare Workers 上,通过 D1 作为数据库、R2 作为对象存储。
部署前请确认以下前置工作已完成:
- Cloudflare 账号凭据已准备好(参见 Cloudflare 集成)
- D1 数据库已创建,已获取 Database ID(参见 数据库)
- R2 存储桶已创建,已获取 存储桶名称(参见 对象存储)
EasyStarter 支持两种部署方式,按需选择:
| 方式 | 适合场景 |
|---|---|
| 方式一:本地 CLI 部署 | 快速上线、一次性部署、完全手动控制 |
| 方式二:GitHub 自动部署 | 持续交付、团队协作、推送即部署 |
方式一:本地 CLI 部署
本地登录 Wrangler 后,手动执行部署命令。
npx wrangler login环境变量说明
Server 端的变量分为三类,分别放在不同位置:
| 类型 | 文件 | 说明 |
|---|---|---|
| 公开配置 | apps/server/wrangler.jsonc → vars | 非敏感值,明文写入配置,随代码部署 |
| 本地开发 | apps/server/.dev.vars | 本地 wrangler dev 自动加载,不参与部署 |
| 生产 Secrets | apps/server/.env.production | 通过 wrangler secret bulk 加密推送到 Workers,不参与构建 |
不要将
.env.production提交到 Git。.dev.vars也应加入.gitignore。
更新 apps/server/wrangler.jsonc
将你的 Worker 名称、D1 Database ID、R2 存储桶名称和公开变量填入配置:
{
"name": "your-server-worker", // Worker 名称,决定默认访问域名,全局唯一
"main": "src/index.ts",
"compatibility_date": "2025-06-15",
"compatibility_flags": ["nodejs_compat"],
"d1_databases": [
{
"binding": "DB",
"database_name": "easystarter-db",
"database_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" // D1 Database ID
}
],
"vars": {
"NODE_ENV": "production",
"WEBSITE_URL": "https://your-app.com", // Web 端公开访问地址
"SERVER_URL": "https://your-server.workers.dev", // Server Worker 自身地址
"GITHUB_CLIENT_ID": "your-github-client-id", // 公开值,无需保密
"GOOGLE_CLIENT_ID": "your-google-client-id" // 公开值,无需保密
},
"r2_buckets": [
{
"binding": "STORAGE",
"bucket_name": "easystarter-bucket" // R2 存储桶名称
}
]
}| 字段 | 说明 |
|---|---|
name | Worker 名称,部署后默认 URL 为 https://<name>.<subdomain>.workers.dev |
database_id | 创建 D1 数据库时获取的 UUID |
vars.WEBSITE_URL | Web 应用地址,用于 Better Auth 的回调 URL、邮件跳转链接等 |
vars.SERVER_URL | Server Worker 自身地址,用于 Better Auth 配置和 CORS |
bucket_name | 与 Cloudflare 后台创建的 R2 存储桶名称保持一致 |
准备生产 Secrets(.env.production)
创建 apps/server/.env.production,填入所有敏感变量。这个文件不参与构建,只用于下一步的 wrangler secret bulk 命令。
# Better Auth — 用于签名会话,必须是足够长的随机字符串
BETTER_AUTH_SECRET=
# GitHub OAuth — 只写 Secret,Client ID 已在 wrangler.jsonc vars 中
GITHUB_CLIENT_SECRET=
# Google OAuth — 只写 Secret,Client ID 已在 wrangler.jsonc vars 中
GOOGLE_CLIENT_SECRET=
# Resend 邮件服务
RESEND_API_KEY=
# R2 公开访问 URL(R2.dev 子域名或自定义域名)
R2_PUBLIC_URL=
# Stripe 支付
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
# RevenueCat(仅启用移动端内购时填写)
REVENUECAT_SECRET_API_KEY=注意事项:
BETTER_AUTH_SECRET建议用openssl rand -base64 32生成,长度至少 32 位GITHUB_CLIENT_SECRET/GOOGLE_CLIENT_SECRET只需要 Secret,对应的 Client ID 已作为公开值放在wrangler.jsonc的vars中R2_PUBLIC_URL是 R2 存储桶对外的访问地址,需要在 R2 后台开启 R2.dev subdomain 或绑定自定义域名后获取- 不使用某项集成(如 RevenueCat)时,对应变量可以留空或删除
部署 Worker
pnpm deploy:server等价于在 apps/server 目录下执行 wrangler deploy,将源码编译后发布到 Cloudflare Workers。
首次部署成功后,控制台会输出 Worker 的访问地址:
Deployed your-server-worker triggers:
https://your-server-worker.your-subdomain.workers.dev记录这个地址,后续配置 Web 端和更新 SERVER_URL 时需要用到。
推送 Secrets
将 .env.production 中的所有变量批量加密写入 Workers Secrets:
pnpm -F server secrets:bulk:production等价于 wrangler secret bulk .env.production。推送后,变量以加密形式存储在 Cloudflare 侧,不会出现在部署代码或日志中。
Secrets 推送和代码部署是独立操作。每次更新敏感变量只需重新推送 Secrets,无需重新部署代码。
运行数据库迁移
将数据库 Schema 应用到 Cloudflare D1。
pnpm db:migrate 使用 drizzle-kit 的 D1 HTTP 驱动,需要以下三个变量在 apps/server/.dev.vars 中已填写:
CLOUDFLARE_ACCOUNT_ID= # Cloudflare 账号 ID
CLOUDFLARE_API_TOKEN= # 有 D1 Edit 权限的 API Token
CLOUDFLARE_D1_DATABASE_ID= # D1 数据库 UUID确认后执行:
pnpm db:migrate迁移成功后,D1 中会创建所有必要的表(用户、会话、订阅、账单等)。
每次修改数据库 Schema 后,先执行
pnpm db:generate生成迁移文件,再执行pnpm db:migrate应用到生产 D1。
验证部署
登录 Cloudflare Dashboard → Workers & Pages,选择刚部署的 Worker,在 Logs 标签下可以实时查看请求日志,确认服务正常响应。
方式二:GitHub 自动部署
将 GitHub 仓库与 Cloudflare 绑定后,每次推送到指定分支都会自动触发构建和部署,无需在本地执行任何命令。
连接 GitHub 仓库
- 进入 Cloudflare Dashboard → Workers & Pages
- 点击 Create → Workers → Connect to Git
- 授权 Cloudflare 访问你的 GitHub 账户,选择对应仓库
- 选择部署分支(通常为
main)
推送 Secrets
在连接仓库后、首次触发构建前,先通过本地 CLI 将所有 Secrets 推送到 Cloudflare,确保 Worker 启动时所有敏感变量已就绪:
pnpm -F server secrets:bulk:production等价于 wrangler secret bulk .env.production,将 apps/server/.env.production 中的所有变量加密写入 Worker Secrets。
Secrets 推送和代码部署是独立操作。后续只有 Secrets 值变更时才需要重新推送,日常代码更新无需重推。
填写构建配置
在 Cloudflare 的构建设置页面填入以下配置:
| 项目 | 值 |
|---|---|
| 根目录 | / |
| 构建命令 | pnpm --filter server build |
| 部署命令 | pnpm --filter server run deploy |
| 版本命令 | pnpm --filter server run deploy |
根目录设置为
/是因为这是 monorepo,pnpm workspace 需要从仓库根目录解析依赖。
运行数据库迁移
自动部署不会自动执行数据库迁移。首次部署完成后,仍需在本地手动运行:
pnpm db:migrate确保 apps/server/.dev.vars 中已填写:
CLOUDFLARE_ACCOUNT_ID=
CLOUDFLARE_API_TOKEN=
CLOUDFLARE_D1_DATABASE_ID=后续每次修改 Schema 时,同样需要在本地执行
pnpm db:generate+pnpm db:migrate。
配置完成后,每次向目标分支推送代码,Cloudflare 都会自动触发构建并部署最新版本。可在 Workers & Pages → 你的 Worker → Deployments 中查看每次部署的状态和日志。
自定义域名(推荐)
- 进入 Workers & Pages → 选择你的 Server Worker → Settings → Domains & Routes
- 点击 Add Custom Domain,输入已托管在 Cloudflare 的域名,例如
api.yourdomain.com - 绑定成功后,按以下说明更新相关配置
为什么必须更新这两个字段
SERVER_URL 和 WEBSITE_URL 不是普通环境变量——它们写在 wrangler.jsonc 的 vars 块中,会在 wrangler deploy 时编译进 Worker Bundle,运行时直接读取。改了值之后必须重新部署才能生效。
这两个字段在认证系统中扮演关键角色:
| 字段 | 用途 |
|---|---|
SERVER_URL | Better Auth 的 baseURL;OAuth 回调地址(/api/auth/callback/github 等);Cookie 的 domain 和 secure 策略 |
WEBSITE_URL | Better Auth 的 trustedOrigins(CORS 白名单);邮件中的跳转链接 |
如果这两个值与实际域名不匹配,OAuth 登录回调会 404,跨域请求会被 CORS 拦截,会话 Cookie 无法写入。
需要修改的文件
"vars": {
"WEBSITE_URL": "https://your-app.com", // Web 端正式域名
"SERVER_URL": "https://api.yourdomain.com" // Server 自定义域名(刚绑定的)
}Web 端也持有 Server 的地址,用于前端直接调用 API:
"vars": {
"VITE_SERVER_URL": "https://api.yourdomain.com" // 与 SERVER_URL 保持一致
}OAuth 应用后台
如果你绑定了新的 SERVER_URL,需要同步更新 OAuth 应用(GitHub / Google)的回调地址:
- GitHub:Settings → Developer settings → OAuth Apps → 更新 Authorization callback URL 为
https://api.yourdomain.com/api/auth/callback/github - Google:Google Cloud Console → 凭据 → OAuth 2.0 客户端 → 更新已授权的重定向 URI
重新部署使配置生效
同时部署 Server 和 Web(因为两边都有改动):
pnpm deploy:server
pnpm deploy:web
vars是随代码打包的静态配置,不是 Secret。每次修改wrangler.jsonc的vars都必须重新执行部署,仅推送 Secrets 不会更新这些值。