---
title: 使用服务端数据库部署 - 配置 Postgres、Clerk 和 S3 存储服务
description: 本文详细介绍如何在 Vercel 中部署服务端数据库版 AiPMChat，包括数据库配置、身份验证服务配置和 S3 存储服务的设置步骤。
tags:
  - 服务端数据库
  - Postgres
  - Clerk
  - S3存储服务
  - Vercel部署
  - 数据库配置
  - 身份验证服务
  - 环境变量配置
---

# 使用服务端数据库部署

AiPMChat 默认使用客户端数据库（IndexedDB），同时也支持使用服务端数据库。AiPMChat 采用了 Postgres 作为后端存储数据库。PostgreSQL是一种强大的开源关系型数据库管理系统，具备高度扩展性和标准SQL支持。它提供了丰富的数据类型、并发处理、数据完整性、安全性及可编程性，适用于复杂应用和大规模数据管理。

本文将详细介绍如何在 Vercel 中部署服务端数据库版 AiPMChat，包括： 1）数据库配置；2）身份验证服务配置；3） S3 存储服务的设置步骤。

<Callout type={'info'}>
  限于工作量原因，目前仅支持在 Vercel 中部署使用服务端数据库版本，Docker 版本将会在后续迭代中支持。
</Callout>

<Callout type={'warning'}>
  进行后续操作前，请务必确认以下事项 -
  导出所有数据，部署服务端数据库后，原有用户数据无法自动迁移，只能提前备份后进行手动导入！ -
  环境变量中的`ACCESS_CODE`未设置或已清除！ -
  配置服务端数据库所需要的环境变量时，需全部填入后再进行部署，否则可能遭遇数据库迁移问题！
</Callout>

## 一、 配置数据库

<Steps>

### 准备服务端数据库实例，获取连接 URL

在部署之前，请确保你已经准备好 Postgres 数据库实例，你可以选择以下任一方式：

- `A.` 使用 Vercel / Neon 等 Serverless Postgres 实例；
- `B.` 使用 Docker 等自部署 Postgres 实例。

两者的配置方式略有不同，在下一步会有所区分。

### 在 Vercel 中添加环境变量

在 Vercel 的部署环境变量中，添加 `DATABASE_URL` 等环境变量，将上一步准备好的 Postgres 数据库连接 URL 填入其中。数据库连接 URL 的通常格式为 `postgres://username:password@host:port/database`。

<Callout type={'warning'}>
  确认您的供应商所提供的`Postgres`类型，若为`Node
  Postgres`，则必须添加环境变量`DATABASE_DRIVER=node`
</Callout>

  <Tabs items={['Serverless Postgres', 'Node Postgres']}>

    <Tab>

      Serverless Postgres 需要填写的变量如下：

      ```shell
      # Serverless Postgres DB Url
      DATABASE_URL=

      # 指定 service mode 为 server，否则不会进入服务端数据库
      NEXT_PUBLIC_SERVICE_MODE=server
      ```

      在 Vercel 中填写的示例如下：

      <Image alt={'添加 Serverless Postgres DATABASE_URL'} src={'https://github.com/aipmhub/aipm-chat/assets/28616219/d4a710cd-6404-4196-90d0-cd08ca385074'}></Image>

</Tab>

    <Tab>
      Node Postgres 需要填写的变量如下：

      ```shell
      # Node Postgres DB Url
      DATABASE_URL=

      # 指定 Postgres database driver 为 node
      DATABASE_DRIVER=node

      # 指定 service mode 为 server，否则不会进入服务端数据库
      NEXT_PUBLIC_SERVICE_MODE=server
      ```

      在 Vercel 中填写的示例如下：

      <Image alt={'添加 Node Postgres DATABASE_URL'} src={'https://github.com/aipmhub/aipm-chat/assets/28616219/1c689738-809b-4199-b305-ba5770d39da7'}></Image>

</Tab>

</Tabs>

<Callout type={'info'}>
  如果希望连接数据库时启用 SSL
  ，请自行参考[链接](https://stackoverflow.com/questions/14021998/using-psql-to-connect-to-postgresql-in-ssl-mode)进行设置
</Callout>

### 添加 `KEY_VAULTS_SECRET` 环境变量

在完成数据库 DATABASE_URL 环境变量添加后，需要添加一个 `KEY_VAULTS_SECRET` 环境变量。该变量用于加密用户存储的 apikey 等敏感信息。你可以使用 `openssl rand -base64 32` 生成一个随机的 32 位字符串作为密钥。

```shell
KEY_VAULTS_SECRET=jgwsK28dspyVQoIf8/M3IIHl1h6LYYceSYNXeLpy6uk=
```

同样需要将其添加到 Vercel 环境变量中。

</Steps>

## 二、 配置身份验证服务

服务端数据库需要搭配用户身份验证服务才可以正常使用。因此需要配置对应的身份验证服务。

<Callout type={'warning'}>
  同样由于工作量原因，目前仅支持 Clerk 作为身份验证服务方案， Next-Auth 的服务端数据库集成有待开发
</Callout>

<Steps>

### 准备 Clerk 身份验证服务

前往 [Clerk](https://clerk.com?utm_source=lobehub&utm_medium=docs) 注册并创建应用，获取相应的 Public Key 和 Secret Key。

<Callout type={'info'}>
  如果对 Clerk 不太了解，可以查阅
  [身份验证服务-Clerk](/zh/docs/self-hosting/advanced/authentication#clerk) 了解 Clerk 的使用详情。
</Callout>

### 在 Vercel 中添加公、私钥环境变量

在 Vercel 的部署环境变量中，添加 `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` 和 `CLERK_SECRET_KEY` 环境变量。你可以在菜单中点击「API Keys」，然后复制对应的值填入 Vercel 的环境变量中。

<Image
  alt={'在 Clerk 中找到对应的公私钥环境变量'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/89883703-7a1a-4a11-b944-5d804544e57c'}
></Image>

此步骤所需的环境变量如下：

```shell
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxx
CLERK_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxx
```

添加上述变量到 Vercel 中：

<Image
  alt={'在 Vercel 中添加 Clerk 公私钥环境变量'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/2bfa13df-6e20-4768-97c0-4dad06c85a2f'}
></Image>

### 在 Clerk 中创建并配置 Webhook

由于我们让 Clerk 完全接管用户鉴权与管理，因此我们需要在 Clerk 用户生命周期变更时（创建、更新、删除）中通知我们的应用并存储落库。我们通过 Clerk 提供的 Webhook 来实现这一诉求。

我们需要在 Clerk 的 Webhooks 中添加一个端点（Endpoint），告诉 Clerk 当用户发生变更时，向这个端点发送通知。

<Image
  alt={'Clerk 添加 Webhooks 端点'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/f50f47fb-5e8e-4930-bf4e-8cf6f5b8afb9'}
></Image>

在 endppint 中填写你的 Vercel 项目的 URL，如 `https://your-project.vercel.app/api/webhooks/clerk`。然后在订阅事件（Subscribe to events）中，勾选 user 的三个事件（`user.created` 、`user.deleted`、`user.updated`），然后点击创建。

<Callout type={'warning'}>URL的`https://`不可缺失，须保持URL的完整性</Callout>

<Image
  alt={'添加 Clerk Webhooks 时，配置 URL 和用户事件'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/0249ea56-ab17-4aa9-a56c-9ebd556c2645'}
></Image>

### 将 Webhook 秘钥添加到 Vercel 环境变量

创建完毕后，可以在右下角找到该 Webhook 的秘钥：

<Image
  alt={'查看 Clerk Webhooks 秘钥'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/fab4abb2-584b-49de-9340-813382951635'}
></Image>

这个秘钥所对应的环境变量名为 `CLERK_WEBHOOK_SECRET`：

```shell
CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxx
```

将其添加到 Vercel 的环境变量中：

<Image
  alt={'在 Vercel 中 添加 Clerk Webhooks 秘钥'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/5fdc9479-007f-46ab-9d6e-a9603e949116'}
></Image>

</Steps>

这样，你已经成功配置了 Clerk 身份验证服务。接下来我们将配置 S3 存储服务。

## 三、 配置 S3 存储服务

AiPMChat 在很早以前就支持了多模态 的 AI 会话，其中涉及到图片上传给 AI 的功能。在客户端数据库方案中，图片文件直接以二进制数据存储在浏览器 indexedDB 数据库，但在服务端数据库中这个方案并不可行。我们需要配置 S3 存储服务来存储大量的图片文件，同时 S3 也可以作为文件上传的存储方案。

<Callout type={'info'}>
  在本文，S3所指代的是指兼容 S3 存储方案，即支持 Amazon S3 API 的对象存储系统，常见例如 Cloudflare
  R2 、阿里云 OSS 等均支持 S3 兼容 API。
</Callout>

<Steps>

    ### 配置并获取 S3 存储桶

    你需要前往你的 S3 服务提供商（如 AWS S3、Cloudflare R2 等）并创建一个新的存储桶（Bucket）。接下来以 Cloudflare R2 为例，介绍创建流程。

    下图是 Cloudflare R2 的界面：

    <Image
      alt={'Cloudflare R2 存储界面'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/41f7f677-0153-4a96-b849-5ac9b7ebefee'}
    ></Image>

    创建存储桶时将指定其名称，然后点击创建。
    <Image
      alt={'R2 创建存储桶'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/9c0d184c-3169-40fa-9115-011cfffb9ca7'}
    ></Image>

    ### 获取存储桶相关环境变量

    在 R2 存储桶的设置中，可以看到桶配置的信息：

    <Image
      alt={'查看存储桶的相关信息'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/2ceb210c-eca0-4439-ba27-8734d4ebb3ee'}
    ></Image>

其对应的环境变量为：

```shell
# 存储桶的名称
S3_BUCKET=aipmchat
# 存储桶的请求端点(注意此处链接的路径带存储桶名称，必须删除该路径，或使用申请 S3 API token 页面所提供的链接)
S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
# 存储桶对外的访问域名
NEXT_PUBLIC_S3_DOMAIN=https://s3-for-aipmchat.your-domain.com
```

<Callout type={'warning'}>`S3_ENDPOINT`必须删除其路径，否则会无法访问所上传文件</Callout>

    ### 获取 S3 密钥环境变量

    你需要获取 S3 的访问密钥，以便 AiPMChat 的服务端有权限访问 S3 存储服务。在 R2 中，你可以在账户详情中配置访问密钥：

    <Image
      alt={'查看存储桶的访问秘钥'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/be0c95c0-6693-44ee-a490-7e8dfaa8b34d'}
    ></Image>

    点击右上角按钮创建 API token，进入创建 API Token 页面

    <Image
      alt={'创建对应 API token'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/7b0ea46c-5157-40a8-888f-f47664a4884f'}
    ></Image>

    鉴于我们的服务端数据库需要读写 S3 存储服务，因此权限需要选择`管理员读与写`，然后点击创建。

    <Callout type={'warning'}>权限必须为`管理员读与写`，否则无法上传照片等其它文件</Callout>

    <Image
      alt={'配置 API token 权限'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/d6f5a918-7b50-4d6e-83a6-3894ab930ddf'}
    ></Image>

    创建完成后，就可以看到对应的 S3 API token

    <Image
      alt={'复制 API token'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/763b18f9-2b5f-44bb-a479-9b56d46f7397'}
    ></Image>

    其对应的环境变量为：

```shell
S3_ACCESS_KEY_ID=9998d6757e276cf9f1edbd325b7083a6
S3_SECRET_ACCESS_KEY=55af75d8eb6b99f189f6a35f855336ea62cd9c4751a5cf4337c53c1d3f497ac2
```

### 在 Vercel 中添加对应的环境变量

    不同 S3 服务商获取所需环境变量的步骤可能有所不同，但最终获得到的环境变量应该都是一致的：

<Callout type={'warning'}>URL的`https://`不可缺失，须保持URL的完整性</Callout>

```shell
# S3 秘钥
S3_ACCESS_KEY_ID=9998d6757e276cf9f1edbd325b7083a6
S3_SECRET_ACCESS_KEY=55af75d8eb6b99f189f6a35f855336ea62cd9c4751a5cf4337c53c1d3f497ac2

# 存储桶的名称
S3_BUCKET=aipmchat
# 存储桶的请求端点
S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
# 存储桶对外的访问域名
NEXT_PUBLIC_S3_DOMAIN=https://s3-dev.your-domain.com

# 桶的区域，如 us-west-1，一般来说不需要添加，但某些服务商则需要配置
# S3_REGION=us-west-1
```

然后将上述环境变量填入 Vercel 的环境变量中：

    <Image
      alt={'在  Vercel 中添加 S3 的环境变量'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/cd74152d-0ae8-44fd-b815-3307c56a3c18'}
    ></Image>

    ### 配置跨域

    由于 S3 存储服务往往是一个独立的网址，因此需要配置跨域访问。

    在 R2 中，你可以在存储桶的设置中找到跨域配置：

    <Image
      alt={'Cloudflare R2 的跨域设置'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/ab008be7-26b2-4b78-8bd9-24301bf34d23'}
    ></Image>

    添加跨域规则，允许你的域名（在上文是 `https://your-project.vercel.app`）来源的请求：

    <Image
      alt={'配置允许你的站点域名'}
      src={'https://github.com/aipmhub/aipm-chat/assets/28616219/dfcc2cb3-2958-4498-a8a4-51bec584fe7d'}
    ></Image>

示例配置如下：

```json
[
  {
    "AllowedOrigins": ["https://your-project.vercel.app"],
    "AllowedMethods": ["GET", "PUT", "HEAD", "POST", "DELETE"],
    "AllowedHeaders": ["*"]
  }
]
```

配置后点击保存即可。

</Steps>

## 四、部署并验证

通过上述步骤之后，我们应该就完成了服务端数据库的配置。接下来我们可以将 AiPMChat 部署到 Vercel 上，然后访问你的 Vercel 链接，验证服务端数据库是否正常工作。

<Steps>
  ### 重新部署最新的 commit

配置好环境变量后，你需要重新部署最新的 commit，并等待部署完成。

<Image
  alt={'重新部署最新的 commit'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/b3a78112-adc8-4837-b4e3-48f67058f16e'}
></Image>

### 检查功能是否正常

如果你点击左上角登录，可以正常显示登录弹窗，那么说明你已经配置成功了，尽情享用吧~

<Image
  alt={'用户登录弹窗'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/da84edc3-46f7-4e2b-a0cd-dc33a98bf5cb'}
></Image>

<Image
  alt={'登录成功状态'}
  src={'https://github.com/aipmhub/aipm-chat/assets/28616219/9cb5150d-6e1e-4c59-9a18-4e418dce1a5d'}
></Image>

</Steps>

## 附录

### 服务端数据库环境变量一览

为方便一键复制，在此汇总配置服务端数据库所需要的环境变量：

```shell
# 指定服务模式为 server
NEXT_PUBLIC_SERVICE_MODE=server

# Postgres 数据库 URL
DATABASE_URL=
KEY_VAULTS_SECRET=jgwsK28dspyVQoIf8/M3IIHl1h6LYYceSYNXeLpy6uk=

# Clerk 相关配置
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxx
CLERK_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxx
CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxx

# S3 相关配置
# S3 秘钥
S3_ACCESS_KEY_ID=9998d6757e276cf9f1edbd325b7083a6
S3_SECRET_ACCESS_KEY=55af75d8eb6b99f189f6a35f855336ea62cd9c4751a5cf4337c53c1d3f497ac2

# 存储桶的名称
S3_BUCKET=aipmchat
# 存储桶的请求端点
S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
# 存储桶对外的访问域名
NEXT_PUBLIC_S3_DOMAIN=https://s3-for-aipmchat.your-domain.com
# 桶的区域，如 us-west-1，一般来说不需要添加，但某些服务商则需要配置
# S3_REGION=us-west-1
```
