> ## Documentation Index
> Fetch the complete documentation index at: https://supastack.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For the full documentation corpus in one file, fetch: https://supastack.dev/llms-full.txt

# 收集其余提供商密钥

剩下这些服务的短演练：AI 提供商、Trigger.dev、S3 存储、Sentry 或 PostHog、Turnstile，以及你的域名。

## 如何使用本页

下面每一节都是一套完整的设置演练：建账户、找密钥、设 env 名、验证。只取你产品要上线的服务对应的节——没有 AI 功能的站点永远不需要第一节；这里的每一节都跳过，套件也照常运行。

与其他地方相同的密钥规则：API 密钥和 webhook 密钥只在服务端；只有带 `NEXT_PUBLIC_`/`EXPO_PUBLIC_` 前缀的值能到客户端；生产密钥放在托管方的密钥存储中；开发服务器只在重启时重新读取 env。

[回到账户清单](https://supastack.dev/zh/docs/web/external-accounts.md)


## AI 提供商密钥

套件的 `AI_PROVIDER` 接受 `openai`、`anthropic`、`openai-compatible` 和 `openrouter`——外加默认的本地替身 `fake`。选一个；提供商密钥是唯一要开的账户，因为模型 ID 和定价来自套件的数据库目录，而不是 env 变量。

OpenAI：[platform.openai.com](https://platform.openai.com) → API keys → Create new secret key → 复制 `sk-…` → `OPENAI_API_KEY`。Anthropic：[console.anthropic.com](https://console.anthropic.com) → API Keys → Create Key → `sk-ant-…` → `ANTHROPIC_API_KEY`。两家都按 token 计费——几美元额度就够开发用了。

OpenRouter 用一把密钥路由目录里的所有模型：[openrouter.ai](https://openrouter.ai) → Keys → Create Key → `sk-or-…` → `AI_PROVIDER=openrouter` 加 `OPENROUTER_API_KEY`；可选的 `OPENROUTER_APP_NAME`/`OPENROUTER_SITE_URL` 发送归属标头。`openai-compatible` 覆盖任何 OpenAI 形态的端点：`OPENAI_COMPATIBLE_API_KEY` 加 `OPENAI_COMPATIBLE_BASE_URL`。

验证：重启，跑一个 AI 任务，应得到真实模型回答而不是确定性的假响应。启动报错点名密钥，表示提供商开关开着却没有密钥。真实回答还需要下面 Trigger.dev 一节的 `JOB_PROVIDER=trigger`，以及套件目录中启用的一个模型——[设置 AI](https://supastack.dev/zh/docs/web/setup-ai.md) 讲了那部分配置。

```
# apps/web/.env.local — pick ONE provider
AI_PROVIDER=openai
OPENAI_API_KEY=sk-…

# or AI_PROVIDER=anthropic
# ANTHROPIC_API_KEY=sk-ant-…

# or AI_PROVIDER=openrouter
# OPENROUTER_API_KEY=sk-or-…

# or AI_PROVIDER=openai-compatible
# OPENAI_COMPATIBLE_API_KEY=…
# OPENAI_COMPATIBLE_BASE_URL=https://your-endpoint/v1
```


## Trigger.dev

除非产品需要真实的后台任务运行，否则跳过——`JOB_PROVIDER=local` 把任务排进内存队列而不执行，开发时这就够了。

1. 打开 [app.trigger.dev](https://app.trigger.dev) → 注册 → 创建项目。

2. 复制两个值：项目 settings 或仪表板 URL 里的项目引用 `proj_…` → `TRIGGER_PROJECT_REF`，以及项目 API keys 页上的密钥（开发环境是 `tr_dev_…`，生产是 `tr_prod_…`）→ `TRIGGER_SECRET_KEY`。两者都仅限服务端。

3. 套件的任务已在 `apps/web/trigger` 中，`apps/web/trigger.config.ts` 读取 `TRIGGER_PROJECT_REF`。在 `apps/web` 下运行 `npx trigger.dev@latest dev`——它把任务注册到你的项目，并用开发密钥在本地运行。

验证：dev 命令会记录注册的任务；在应用中排一个任务，看它在仪表板 Runs 列表里跑起来。已部署环境运行 `corepack pnpm --filter @supastack/web trigger:deploy` 来发布任务集。

```
# apps/web/.env.local
JOB_PROVIDER=trigger
TRIGGER_PROJECT_REF=proj_…
TRIGGER_SECRET_KEY=tr_dev_…   # tr_prod_… in production

# run the worker alongside the app, from apps/web:
cd apps/web
npx trigger.dev@latest dev
```


## S3 兼容存储（Cloudflare R2）

除非产品要存文件，否则跳过——`STORAGE_PROVIDER=memory` 把上传留在进程内，供开发使用。

任何 S3 兼容桶都行；Cloudflare R2 是对免费档友好的选择。1. 打开 [dash.cloudflare.com](https://dash.cloudflare.com) → R2 Object Storage → Create bucket，命名并保留默认位置提示。

2. 回到 R2 概览，打开 Manage R2 API Tokens → Create API token → 权限选 Object Read & Write，范围限定到那个桶 → Create。复制 Access Key ID、Secret Access Key，以及显示的 S3 端点——`https://<account-id>.r2.cloudflarestorage.com`。

3. 设置下面的 env 名。`STORAGE_REGION=auto` 是 R2 惯例——套件默认 `us-east-1`，R2 也接受。`STORAGE_FORCE_PATH_STYLE` 对自定义端点本来就默认开启，正是 R2 要的。对外提供公开文件还需要 `STORAGE_PUBLIC_BASE_URL` 或 CDN 接线；私有文件不需要更多。

验证：重启并通过应用上传——对象会出现在 R2 桶浏览器里。签名或 403 错误表示令牌没有该桶的对象读写权限；建一个范围正确的新令牌。

```
# apps/web/.env.local
STORAGE_PROVIDER=s3
STORAGE_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
STORAGE_REGION=auto
STORAGE_BUCKET=your-bucket
STORAGE_ACCESS_KEY_ID=…          # server-only
STORAGE_SECRET_ACCESS_KEY=…      # server-only
# STORAGE_PUBLIC_BASE_URL=       # optional public-URL base
```


## Sentry 或 PostHog（可选）

完全可选：所有可观测性值默认不设置，套件没有它们也运行良好——等你想在生产里要错误报告和分析时再配。

错误用 Sentry：[sentry.io](https://sentry.io) → 建项目 → 选 Next.js 平台 → 设置页显示 DSN `https://…@….ingest.sentry.io/…` → `SENTRY_DSN`。之后异常会带着 correlation-id 标签到达 Sentry；免费档够起步。

产品分析改用 PostHog：[posthog.com](https://posthog.com) → 建项目 → 复制项目 API 密钥 `phc_…` → `NEXT_PUBLIC_POSTHOG_KEY` 加 `NEXT_PUBLIC_POSTHOG_HOST`（`https://us.i.posthog.com`，或你的 EU 主机）。这两个是刻意公开的浏览器值；`SENTRY_DSN` 留在服务端。`ALERT_WEBHOOK_URL` 可选地把失败告警发到 Slack 兼容端点。

验证：重启，制造一个测试异常（或回放 Sentry 的示例事件），确认它落到项目的 Issues 列表里。

```
# apps/web/.env.local — all optional
SENTRY_DSN=https://…@….ingest.sentry.io/…

NEXT_PUBLIC_POSTHOG_KEY=phc_…
NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com

# ALERT_WEBHOOK_URL=https://hooks.slack.com/services/…
```


## Cloudflare Turnstile

给公开表单和凭据端点的机器人防护——`CAPTCHA_PROVIDER=off` 是默认，所以在对陌生人开放注册前加上它。免费。

1. 打开 [dash.cloudflare.com](https://dash.cloudflare.com) → Turnstile → Add widget → 命名并列出主机名：开发用 `localhost` 加你的真实域名 → Create。

2. 复制两个值：Site Key——本来就公开，渲染在小组件里 → `NEXT_PUBLIC_TURNSTILE_SITE_KEY`——和服务器用来校验的 Secret Key → `TURNSTILE_SECRET_KEY`。

3. `CAPTCHA_PROVIDER=turnstile` 开启它；启动会失败并点名缺了哪个密钥。验证码指南列出了小组件具体保护哪些面。

验证：打开 `/auth` 或联系表单——小组件渲染出来；未完成挑战的提交被拒绝。小组件一直不加载，说明你浏览的主机名不在小组件名单里。

[看看 Turnstile 保护哪些表单](https://supastack.dev/zh/docs/web/captcha.md)

```
# apps/web/.env.local
CAPTCHA_PROVIDER=turnstile
NEXT_PUBLIC_TURNSTILE_SITE_KEY=0x…   # public by design
TURNSTILE_SECRET_KEY=0x…             # server-only
```


## 你自己的域名

在任意注册商买一次就行——Cloudflare Registrar、Porkbun、Namecheap 都可以。这里没有要复制进 env 的东西；域名出现在你一路配置的 Services ID、Resend DNS、Turnstile 主机名和 OAuth return URL 里。

指向应用的两种方式：Cloud Run 用部署指南里的域名映射——控制台点几下，加上 Google 列出的 DNS 记录。或者把 DNS 迁到 Cloudflare nameserver（注册商改两条记录）——可选，但也是把 R2 公开桶和 Turnstile 主机名放到一处管理的整洁办法。

[在 Cloud Run 上映射域名](https://supastack.dev/zh/docs/web/deploy-google-cloud.md)

[接下来设置数据库](https://supastack.dev/zh/docs/web/setup-database.md)


如果你想继续完成设置，可以阅读《[设置数据库](https://supastack.dev/zh/docs/web/setup-database.md)》。


## 下一篇

[设置数据库](https://supastack.dev/zh/docs/web/setup-database.md)
