> ## 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

# 部署到 Google Cloud

在 Cloud Build 上构建套件的 Docker 镜像，用托管密钥在 Cloud Run 上运行，并绑定你的域名。

## 初学者演练

前提条件：应用在本地可用、一个可以从互联网访问的真实数据库（设置数据库），以及你要上线的功能对应的服务商账户。你需要一个 Google 账户；配置结算时会要求绑定银行卡，尽管轻度使用仍在免费额度内。

快速术语：容器镜像是应用打包后的副本，任何主机都能运行。Artifact Registry 是 Google 存放镜像的仓库。Cloud Build 在 Google 的机器上构建镜像——本地不需要 Docker。Cloud Run 把镜像作为 HTTPS 服务运行并自动扩缩。Secret Manager 保存密码和密钥。修订版本（revision）是服务的一次部署版本。

你将构建的内容：一个 Google Cloud 项目、一个存放镜像的 Artifact Registry 仓库、一个通过 HTTPS 提供应用的 Cloud Run 服务、存放在 Secret Manager 中的密钥，以及一个托管 Postgres。套件根目录的 `Dockerfile` 已经能产出一个监听 8080 端口的独立 Next.js 服务器——正是 Cloud Run 所期望的。

诚实的成本说明：Cloud Run 的免费额度可以覆盖轻度流量，但 Cloud SQL——Google 的托管 Postgres——没有免费层。Supabase 或 Neon 的免费数据库是最便宜的起步方式；本指南走这条路。建议在 Billing → Budgets & alerts 下添加预算提醒，然后再开始折腾。

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

[先创建 OAuth 账户](https://supastack.dev/zh/docs/web/external-accounts.md)


## 创建账户并安装 CLI

1. 打开 [console.cloud.google.com](https://console.cloud.google.com)，用你的 Google 账户登录并接受条款。

2. 按提示关联结算：Billing → Link a billing account → Create billing account。激活账户需要银行卡；试用额度可以覆盖早期实验。

3. 点击项目下拉菜单 → New Project，命名并 Create——或复用你为 Google 登录创建的项目；一个项目就够了。

4. 从 [cloud.google.com/sdk](https://cloud.google.com/sdk/docs/install) 安装 Google Cloud CLI：下载适合你操作系统的安装程序并完成安装，然后打开一个新终端，让 `gcloud` 命令可用。

5. 运行下面两条命令。第一条会打开浏览器为 CLI 授权；第二条选择你的项目——使用控制台仪表板上显示的项目 ID，它不一定和名称相同。

预期结果：`gcloud config list` 显示你的账户和项目。如果 `gcloud` 无法识别，重新打开终端或先完成安装程序。

```
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
```


## 创建生产数据库

新手路径——Google 之外的托管 Postgres。在 [supabase.com](https://supabase.com)：New project → 选择名称、数据库密码和区域 → 等待初始化 → Project Settings → Database。Supabase 提供两种连接串：5432 端口的会话池/直连，和 6543 端口的事务池——5432 串用于迁移和长连接客户端，6543 串用于无服务器应用。在 [neon.tech](https://neon.tech)：New project → 复制它显示的连接串。两者都可以；保持密码部分完整。

把直连/会话串放进根目录 `.env` 的 `DATABASE_URL`——迁移工具读取根目录文件且需要会话连接——以及 `apps/web/.env.local` 供本地开发服务器使用。然后从仓库根目录运行一次迁移命令，在新数据库中创建套件的表。已部署应用使用的 `DATABASE_URL` 密钥也可以换成 6543 的池化串。

Google 原生替代方案是 Cloud SQL——同一项目内的托管 Postgres。它没有免费层，且私有 IP 连接需要 VPC 连接器——把它当作以后的升级，而不是起点。

```
# DATABASE_URL=<the direct/session Postgres string, port 5432> in .env + apps/web/.env.local, then:
corepack pnpm --filter @supastack/db db:migrate
```


## 启用服务并推送镜像

从仓库根目录运行下面的命令。它们会启用本次部署用到的四个 Google 服务、在 Artifact Registry 中创建 Docker 仓库，并把仓库提交给 Cloud Build——它在远端构建根目录的 `Dockerfile`，因此不需要 Docker Desktop。

替换 `YOUR_PROJECT_ID`，并选择一个区域——下面是 `us-central1`——仓库和服务都复用它。预期结果：构建日志滚动数分钟，以 `DONE` / `STATUS: SUCCESS` 结束。随后镜像会出现在控制台的 Artifact Registry → supastack → web 下。

```
gcloud services enable run.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com secretmanager.googleapis.com

gcloud artifacts repositories create supastack --repository-format=docker --location=us-central1

gcloud builds submit --tag us-central1-docker.pkg.dev/YOUR_PROJECT_ID/supastack/web:latest
```


## 把密钥存入 Secret Manager

密钥绝不能进入 `--set-env-vars` 或镜像——两者都以明文存储，任何能读取服务配置的人都看得见。Secret Manager 让它们保持加密并在运行时注入。

1. 在控制台打开 Security → Secret Manager → Create Secret。

2. 创建 `DATABASE_URL`，值为完整的 Postgres 连接串——池化的无服务器串对应用来说就可以；`AUTH_SECRET`，至少 32 个随机字符（`openssl rand -hex 32` 可以生成一个）；以及 `CREDENTIAL_ENCRYPTION_KEY`，值为 Base64 编码的 32 字节密钥（`openssl rand -base64 32`）；它用于加密工作区在应用中保存的服务商密钥。

3. 为每个已启用的服务商各建一个密钥——例如 `STRIPE_SECRET_KEY` 加 `STRIPE_WEBHOOK_SECRET`、`RESEND_API_KEY`、`GOOGLE_CLIENT_SECRET`、`GITHUB_CLIENT_SECRET`。像 `EMAIL_PROVIDER=resend` 这样的非机密设置保持为普通环境变量，不要做成密钥。

服务第一次引用某个密钥时，它的运行时服务账户需要读取权限——通过控制台的服务编辑器挂载密钥时，Google 会自动提供该授权；在 CLI 上，部署错误会报出需要授予的 Secret Manager 角色名。

```
# Secrets to create in Secret Manager:
DATABASE_URL     # Postgres connection string — the pooled serverless string is fine
AUTH_SECRET      # openssl rand -hex 32
CREDENTIAL_ENCRYPTION_KEY   # openssl rand -base64 32

# plus one per enabled provider, e.g.:
STRIPE_SECRET_KEY
STRIPE_WEBHOOK_SECRET
RESEND_API_KEY
GOOGLE_CLIENT_SECRET
GITHUB_CLIENT_SECRET
```


## 部署 Cloud Run 服务

控制台路径：Cloud Run → Create service → Deploy one revision from an existing container image → 选择刚推送的 `…/supastack/web:latest` 镜像 → 选择相同区域 → 在 Authentication 下选择 Allow unauthenticated invocations（这是一个公开应用）→ Create。

下面的 CLI 等价命令在同一步骤中加上环境变量接线。明文配置放进 `--set-env-vars`；密钥在 `--set-secrets` 中按 Secret Manager 名称引用。把你的服务商开关（`EMAIL_PROVIDER`、`BILLING_PROVIDER`、`AI_PROVIDER`、`JOB_PROVIDER`）作为普通环境变量与 `APP_URL` 并列添加。

`APP_ENV=production` 是必需的——没有它，应用会以 `local` 模式启动：生产配置校验被跳过，安全 cookie 前缀保持关闭，仅限开发的 `/mail-preview` 页面仍然公开可访问（当 `EMAIL_PROVIDER=local` 时会泄露本地邮件发件箱）。生产环境在启动时还需要另外四个值：`EXPO_PUBLIC_API_URL` 是移动应用访问 API 所用的公开 https URL——设为服务 URL（纯 Web 部署时与 `APP_URL` 相同）；`EXPO_PUBLIC_APP_SCHEME` 是移动端深链 scheme——不上线移动应用时，任何合法值如 `supastack` 都可以；`MOBILE_ALLOWED_ORIGINS` 是服务器信任的精确 https origin 的逗号分隔列表——你的应用 URL 就是正确的起点，通配符会被拒绝；`CREDENTIAL_ENCRYPTION_KEY` 加密已保存的服务商凭据，留在 Secret Manager 中。

首次部署时 Cloud Run 会分配一个 `https://….run.app` URL，而应用的 `APP_URL` 必须等于它的真实公开 URL，认证回调和链接才能工作。所以先用占位符部署一次，从服务页面复制 `*.run.app` URL，然后更新服务（控制台：Edit & deploy new revision，或重新运行该命令），把 `APP_URL`——以及对应的 `EXPO_PUBLIC_API_URL` / `MOBILE_ALLOWED_ORIGINS` 值——设置为它。容器端口保持 8080——Cloud Run 的默认值已经与 `Dockerfile` 的 `PORT` 一致。

```
gcloud run deploy supastack --image us-central1-docker.pkg.dev/YOUR_PROJECT_ID/supastack/web:latest --region us-central1 --allow-unauthenticated --set-env-vars "APP_ENV=production,APP_URL=https://YOUR_SERVICE_URL,EXPO_PUBLIC_API_URL=https://YOUR_SERVICE_URL,EXPO_PUBLIC_APP_SCHEME=supastack,MOBILE_ALLOWED_ORIGINS=https://YOUR_SERVICE_URL" --set-secrets "DATABASE_URL=DATABASE_URL:latest,AUTH_SECRET=AUTH_SECRET:latest,CREDENTIAL_ENCRYPTION_KEY=CREDENTIAL_ENCRYPTION_KEY:latest"
```


## 绑定你自己的域名（可选）

测试期间可以跳过——`*.run.app` URL 已经提供 HTTPS。准备好后：Cloud Run → 你的服务 → Custom Domains / Domain Mappings → Add mapping → 选择服务并输入你的域名。

如有提示请验证域名所有权（Google 会引导你完成），然后在你的域名注册商处创建映射屏幕列出的 DNS 记录。记录生效后，托管的 HTTPS 证书会自动签发——通常几分钟，最长一天。

域名开始承载流量后，把 `APP_URL` 更新为 `https://yourdomain.com`，并注册对应的 OAuth redirect URI（`https://yourdomain.com/api/auth/callback/…`）——登录指南会说明在哪里配置。


## 验证部署

打开 `https://YOUR_SERVICE_URL/api/health`——应返回 `ok`。然后端到端走一遍应用：打开 URL、注册、请求邮件验证码、确认它能到达收件箱（这需要 `EMAIL_PROVIDER=resend`、`RESEND_API_KEY` 和已验证的发件人——本地适配器永远到不了真实收件箱）、登录并使用一个你启用的功能。

Cloud Run → 你的服务 → Logs 显示请求和错误输出。如果部署出问题，Revisions 选项卡提供一键回滚到上一个修订版本。

移动端和桌面客户端必须指向这个 HTTPS 后端：Expo 用 `apps/mobile/.env.local` 中的 `EXPO_PUBLIC_API_URL`，桌面外壳用 `SUPASTACK_APP_URL`。

[创建移动端账户](https://supastack.dev/zh/docs/mobile/external-accounts.md)

[运行完整部署清单](https://supastack.dev/zh/docs/web/deployment.md)


如果你想继续完成设置，可以阅读《[部署清单](https://supastack.dev/zh/docs/web/deployment.md)》。


## 下一篇

[部署清单](https://supastack.dev/zh/docs/web/deployment.md)
