快速部署
本页带你在 5 分钟内用 Docker Compose 拉起一套完整的 Aivory 生产栈:PostgreSQL、Redis、Qdrant、内置代码沙箱,以及一个同时伺服前端 SPA 和 /api 后端的 app 容器(二者同源,无需任何域名或 CORS 配置)。
整套栈由一份 compose 文件描述,包含以下服务:
| 服务 | 镜像 | 作用 |
|---|---|---|
postgres | postgres:16-alpine | 关系型存储:用户、对话、知识库、用量等 |
redis | redis:7-alpine | 缓存、限流计数器、跨进程停止流式输出的 pub/sub |
qdrant | qdrant/qdrant:v1.12.4 | RAG 向量检索 |
sandbox | ghcr.io/hjxwz123/aivory-sandbox-sidecar | 内置代码执行沙箱,仅内网可达 |
app | ghcr.io/hjxwz123/aivory-app | 单容器同源伺服 SPA 与 /api |
Aivory 的后端按环境变量自动选型:不配 PostgreSQL 就用内嵌 SQLite,不配 Redis 就用进程内缓存,不配 Qdrant 则 RAG 回退为全文注入。想用最小依赖跑单机,见 SQLite 模式。本页描述的是推荐的完整生产部署。
前置要求
| 项目 | 要求 |
|---|---|
| Docker Engine | 已安装并可正常运行(docker info 无报错) |
| Docker Compose | v2(docker compose 子命令,不是旧版 docker-compose) |
| 机器规格 | 2 核 CPU + 4 GB 内存起步 |
| 端口 | 宿主机 80 端口空闲(可改,见下文) |
| 磁盘 | 数据库、向量、上传文件均持久化在本机,按使用量预留 |
内置代码沙箱通过挂载的 /var/run/docker.sock 在宿主机上派生每会话的隔离容器,因此宿主机必须能直接运行 Docker(不适用于无 Docker 守护进程的托管容器平台)。沙箱服务不发布任何宿主端口,只在私有网络内被 app 访问。
第 1 步:获取代码
git clone https://github.com/hjxwz123/Aivory.git
cd Aivory/deploy
部署相关的全部文件都在 deploy/ 目录下:docker-compose.prod.yml 和 .env.example。
第 2 步:创建并编辑 .env
cp .env.example .env
.env 中必须修改的只有三项,其余全部可以保持默认。三项都留着占位值会导致启动失败或严重安全问题:
# 生成三个强随机值
openssl rand -hex 24 # 用作 POSTGRES_PASSWORD
openssl rand -hex 24 # 用作 REDIS_PASSWORD
openssl rand -hex 32 # 用作 JWT_SECRET
| 变量 | 要求 | 说明 |
|---|---|---|
POSTGRES_PASSWORD | 必设 | PostgreSQL 密码。不设置时 compose 直接拒绝启动 |
REDIS_PASSWORD | 必设 | Redis 密码。不设置时 compose 直接拒绝启动 |
JWT_SECRET | 必设,长度至少 32 字符 | 签发登录令牌的密钥。生产环境下 Aivory 检测到占位值或过短密钥会拒绝启动 |
请务必使用 openssl rand -hex 32 生成,不要用可猜测的字符串。同时注意:更换 JWT_SECRET 会使所有已登录会话失效。
模型服务商的 API Key(Anthropic / OpenAI / Gemini 等)不在 .env 里配置,它们存在数据库的渠道表中,部署完成后在管理后台添加,见首次运行配置。
第 3 步:启动
方式一,拉取预构建镜像(推荐,来自 GitHub Container Registry):
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
方式二,本地从源码构建(在代码上做了修改,或官方镜像未覆盖你的 CPU 架构时):
docker compose -f docker-compose.prod.yml up -d --build
app 服务同时声明了 image: 和 build::本地存在预构建镜像时 Compose 优先使用镜像,否则回退到本地构建。数据库 schema 由应用启动时自动迁移创建,不需要手动执行任何 SQL。
第 4 步:验证
docker compose -f docker-compose.prod.yml ps
预期看到 5 个服务:postgres、redis 处于 healthy,qdrant、app 处于 running,sandbox 首次启动时需要先拉取沙箱运行时镜像,健康检查预留了 120 秒启动窗口,稍等即可变为 healthy。
然后请求首页。app 容器内部监听 8787 端口,compose 默认把它映射到宿主机 80 端口:
curl -sI http://localhost
返回 HTTP/1.1 200 且内容为 SPA 页面即部署成功。如果你把端口映射改成了别的(例如 8080:8787),把命令里的端口对应替换。
端口映射不走环境变量,直接编辑 docker-compose.prod.yml 中 app 服务的 ports 段,把 "80:8787" 的左边改掉(例如 "8080:8787"),右边的 8787 是容器内监听端口,不要改。
第 5 步:打开站点,进入首启设置
浏览器访问 http://<你的服务器 IP 或域名>。全新部署没有任何用户,页面会自动进入首启设置:你创建的第一个账号立即成为管理员。接下来的建号、添加渠道、创建模型等步骤,见首次运行配置。
一条龙命令
以下命令块从零完成:克隆、生成密钥、写入 .env、拉镜像、启动。适合在一台全新机器上直接粘贴执行:
git clone https://github.com/hjxwz123/Aivory.git \
&& cd Aivory/deploy \
&& cp .env.example .env \
&& sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 24)|" .env \
&& sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -hex 24)|" .env \
&& sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$(openssl rand -hex 32)|" .env \
&& docker compose -f docker-compose.prod.yml pull \
&& docker compose -f docker-compose.prod.yml up -d \
&& docker compose -f docker-compose.prod.yml ps
上面的命令把随机密钥直接写进了 deploy/.env。这个文件等同于你部署的钥匙串,请纳入备份,不要提交到公开仓库。
.env.example 变量逐条说明
下面按 .env.example 中的分组逐条解释每个变量该不该改。
镜像来源
| 变量 | 默认值 | 该不该改 |
|---|---|---|
IMAGE_OWNER | hjxwz123 | 一般不改。只有当你 fork 了仓库并用自己的 GHCR 命名空间发布镜像时才改成自己的账号 |
IMAGE_TAG | latest | 一般不改。如需锁定版本,改为对应的镜像标签,避免 latest 漂移 |
网络与跨域
| 变量 | 默认值 | 该不该改 |
|---|---|---|
ALLOWED_ORIGINS | 未设置(注释状态) | 保持不设。单容器部署里 SPA 与 /api 同源,不存在跨域;仅当你把前端拆到与 API 不同的 origin 时才需要。域名与 HTTPS 见反向代理 |
注意:没有 WEB_PORT 或 PUBLIC_ORIGIN 这类变量。宿主端口在 compose 文件里改;域名不需要配置,容器被哪个 host 访问,哪个 host 就能用,多个域名同时指向也可以。
PostgreSQL
| 变量 | 默认值 | 该不该改 |
|---|---|---|
POSTGRES_USER | aivory | 不必改 |
POSTGRES_DB | aivory | 不必改 |
POSTGRES_PASSWORD | 占位值 | 必改,openssl rand -hex 24 |
Redis
| 变量 | 默认值 | 该不该改 |
|---|---|---|
REDIS_PASSWORD | 占位值 | 必改,openssl rand -hex 24 |
Qdrant
| 变量 | 默认值 | 该不该改 |
|---|---|---|
QDRANT_URL | http://qdrant:6333 | 不必改。只有指向外部 Qdrant 集群时才覆盖 |
QDRANT_API_KEY | 空 | 可不改。留空时 qdrant 服务与 app 共用同一个内置内部密钥,开箱即用;Qdrant 不发布任何宿主端口,仅内网可达。想要独立强密钥可用 openssl rand -hex 24 覆盖 |
认证
| 变量 | 默认值 | 该不该改 |
|---|---|---|
JWT_SECRET | 占位值 | 必改,openssl rand -hex 32,至少 32 字符,否则生产环境拒绝启动 |
数据目录与备份
| 变量 | 默认值 | 该不该改 |
|---|---|---|
DATA_DIR | ./data | 视磁盘规划而定。宿主机路径,绑定挂载到容器 /app/data,存放用户上传文件与生成产物,必须纳入备份 |
BACKUP_DIR | /app/data/backups | 不必改。容器内路径,管理后台异步生成的全量迁移 ZIP 存放处,宿主机上对应 DATA_DIR/backups |
MAX_BACKUP_BYTES | 21474836480(20 GiB) | 一般不改。管理后台导入备份的大小上限,含向量数据的全量包可能很大,超限时调大 |
数据库、Redis、Qdrant 的数据分别在命名卷 pgdata、redisdata、qdrantdata 中,备份策略见备份与迁移。
演示模型
| 变量 | 默认值 | 该不该改 |
|---|---|---|
ENABLE_MOCK_PROVIDER | false | 可选。设为 true 会注入一个内置演示渠道,不需要任何真实 API Key 就能端到端跑通对话,适合先验证部署;在管理后台添加真实渠道后改回 false |
联网搜索(可选)
| 变量 | 默认值 | 该不该改 |
|---|---|---|
SEARCH_PROVIDER | 空 | 可选。搜索后端类型:serper / brave 需配 SEARCH_API_KEY;searxng 需配 SEARCH_BASE_URL,无需 key |
SEARCH_API_KEY | 空 | 随 SEARCH_PROVIDER 而定 |
SEARCH_BASE_URL | 空 | 仅 searxng 类后端需要 |
这三项也可以部署后在管理后台在线配置,.env 里的值只是启动期兜底,可以先全部留空。
嵌入模型(可选,知识库检索质量相关)
| 变量 | 默认值 | 该不该改 |
|---|---|---|
EMBEDDING_BASE_URL | 空 | 建议生产配置。留空时使用内置 256 维本地 embedder,可用但检索质量不适合生产;指向任意 OpenAI 格式的 /v1/embeddings 端点即可 |
EMBEDDING_API_KEY | 空 | 随嵌入服务而定 |
EMBEDDING_MODEL | text-embedding-3-small | 按你的嵌入服务改 |
EMBEDDING_DIM | 1536 | 必须与嵌入模型的输出维度一致。Qdrant 按维度使用独立 collection,维度不匹配会退回本地 256 维 embedder |
MinerU 文档解析(可选)
| 变量 | 默认值 | 该不该改 |
|---|---|---|
MINERU_API_URL | https://mineru.net | 一般不改 |
MINERU_API_KEY | 空 | 可选。用于扫描版 / 图片型 PDF 的 OCR 解析;不配置时这类文档仍能上传进知识库,但内容只有一行占位文本。也可部署后在管理后台配置 |
代码沙箱(注释状态,通常什么都不用设)
沙箱服务随本栈一起启动,app 通过私有网络访问它,双方共享同一个内置默认密钥,开箱即用。仅在需要覆盖默认限额时取消注释:
| 变量 | 默认值 | 说明 |
|---|---|---|
SANDBOX_API_KEY | 内置共享默认值 | 想用自定义密钥时设置,app 与 sandbox 会同时读到 |
SANDBOX_MEMORY | 2g | 每个会话容器的内存上限 |
SANDBOX_CPUS | 1 | 每个会话容器的 CPU 配额 |
SANDBOX_MAX_SESSIONS | 16 | 并发沙箱会话数上限 |
SANDBOX_WORKSPACE_SIZE | 512m | 每会话 /workspace 大小 |
SANDBOX_NETWORK | none | 沙箱内代码默认无网络;确需联网时才改为 bridge |
沙箱架构与安全边界详见代码沙箱部署。同时请保持管理后台设置里的 sandbox_base_url / sandbox_api_key 两个字段为空,这样内置沙箱才会生效。
下一步
- 首次运行配置:创建管理员、添加渠道与模型、发出第一条消息
- 反向代理与 HTTPS:公网部署必读,给 80 端口的明文 HTTP 加上 TLS 终止层
- Cloudflare 接入:使用 Cloudflare 时的注意事项
- 核心环境变量:全部部署级变量的完整参考