安装
本页介绍将 PlantPulse Studio 安装到客户一台服务器上的步骤。 它由 4 个 Docker 容器(Web · Server · Builder Sidecar · Docker Proxy)组成,安装脚本 会自动处理从 Docker 安装到启动的所有事项。
我们使用的是外部 PG —— 可以复用平台所用的同一个 PG。以前曾经有一种启动捆绑容器的 模式,但现在已经移除了(2026-08-28)—— 实际上曾发生在一台服务器上因使用 5432 端口而发生冲突的事故。
如果是无法连接互联网的隔离网络,请改用 隔离网络安装 而不是本文档。
1. 前置要求
服务器规格
| 项目 | 最低配置 | 推荐配置 | 备注 |
|---|---|---|---|
| CPU | 4 核 | 8 核及以上 | 每个应用会话都会运行构建 |
| 内存 | 8 GB | 16 GB 及以上 | 参见下表 |
| 磁盘 | 50 GB 可用空间 | 100 GB 及以上 | 仅容器镜像就约需 6 GB |
| 操作系统 | Linux (x86_64) | RHEL 9 / Rocky 9 / Ubuntu 22.04 及以上 | 只需能运行 systemd + Docker 即可 |
内存计算依据 —— 这是技术栈固定的上限值。
| 容器 | 内存上限 |
|---|---|
| studio-server (编排器) | 2 GB |
| agent-server (构建器边车) | 2 GB (可通过 AGENT_SERVER_MEMORY 调整) |
| studio-web (nginx) | 256 MB |
| docker-proxy (Docker 通道) | 128 MB |
| 每个应用会话容器 | 2 GB |
应用会话容器在用户每次打开项目时启动一个,若 30 分钟未使用会自动回收。 请按照同时工作的用户数,额外增加 2 GB 内存。
以 16 GB 内存 · 8 核 · 100 GB 磁盘为基准进行配置,就绰绰有余了。
软件
- Docker Engine + Docker Compose v2 (v2.22 或更高版本) 如果未安装,一行安装脚本会自动进行安装。
curl、tar(大多数发行版已内置)
端口与防火墙
技术栈使用 host 网络运行。也就是说,容器端口会直接映射到宿主机上, 因此访问控制只能通过服务器防火墙来实现。
| 端口 | 用途 | 防火墙 |
|---|---|---|
| 80 | Studio 界面 (nginx) | 开放 |
| 5171 | 应用监听器 —— 预览 · 部署应用 · 二维码访问 | 开放(必须) |
| 5170 | Studio API | Web 内部代理 —— 无需开放(用于诊断) |
| 8000 | 构建器边车 (agent-server) | 仅限回环 —— 严禁开放 |
| 5172 | MCP 工具桥接 | 仅限回环 —— 严禁开放 |
| 2375 | Docker 守护进程通道 (docker-proxy) | 仅绑定到 127.0.0.1 —— 技术栈中唯一不使用 host 网络的容器 |
预览(/preview/…)和部署应用(/apps/…)由于安全边界的原因,在与 Studio 不同的源(默认 5171 端口)上提供服务。
这是为了阻止通过聊天创建的应用的 JavaScript 访问 Studio 登录
令牌而设置的机制。如果不开放 5171 端口,屏幕将显示为空白。
这两个端口专用于内部组件之间的通信,并且没有认证流程。如果暴露到外部,整个 用户工作区都将可被读写。技术栈默认只绑定到回环地址, 但请绝对不要在防火墙中开放它们。
仓库访问
镜像从 KOPENS 仓库(docker.kopens.io)获取。安装前请先登录一次。
账户由 KOPENS 运营团队发放。
docker login docker.kopens.io
2. 数据库准备
Studio 使用外部 PostgreSQL。 可以复用平台所用的同一个 PG。
DATABASE_URL 是必填项如果为空,安装会在当前位置停止,并提示哪个值为空 —— 我们不会编造一个看似合理的默认值。 因为曾经发生过默认值指向错误位置而导致事故的情况。
DATABASE_URL=postgres://`<user>`:`<password>`@`<db-host>`:5432/`<db-name>`
先创建数据库和账户
🔴 服务器只对 «已存在» 的数据库执行迁移。它不会创建数据库和角色。 有单独的脚本来负责创建这些。
# .env 의 DATABASE_URL 이 가리키는 DB · 역할을 만든다
bin/provision-platform-db.sh
# 관리자 계정을 따로 줘야 하는 경우
ADMIN_URL=postgres://`<관리자>`:`<password>`@`<호스트>`:5432/postgres bin/provision-platform-db.sh
# 무엇을 할지 보기만 한다
DRYRUN=1 bin/provision-platform-db.sh
AI 部分也遵循相同的规则。
3. 安装(一行命令 · 推荐)
以 root 用户登录服务器,执行一行命令即可。脚本会完成 Docker 检查/安装 → 下载包 →
生成 .env → 启动技术栈。
curl -fsSL https://product.kopens.io/plantpulse-studio/install.sh | sudo bash
安装位置为 /opt/kopens/plantpulse-studio-docker,之后所有运维命令都在此目录下执行。
预定义值进行无人值守安装
环境变量必须放在 bash 之前,才能通过管道传递。
curl -fsSL https://product.kopens.io/plantpulse-studio/install.sh \
| sudo PLATFORM_API_TARGET=https://192.168.0.41 \
DATA_ROOT=/data1/pp-studio \
PS_ANTHROPIC_API_KEY=sk-ant-... \
bash
交互式询问值
curl -fsSL https://product.kopens.io/plantpulse-studio/install.sh | sudo INTERACTIVE=1 bash
如果在已安装的服务器上重新执行,由于边车中已有值,会跳过整个交互提示。 上面的画面是干净设备的首次安装。
需要询问的只有五项(自 2026.09 起)。其余七项使用默认值,并在安装结束时打印出这些默认值 —— 并非隐藏,而是展示后跳过。
| 顺序 | 询问内容 | 变量 |
|---|---|---|
| 1 | 平台 API 服务器 (https://…) | PP_API_URL |
| 2 | 平台 API 令牌 (X-API-Key) | PP_API_TOKEN |
| 3 | AI 网关地址 — 需包含 /v1 部分 | PI_LLM_URL |
| 4 | AI 网关密钥 (LiteLLM 主密钥) | PI_LLM_API_KEY |
| 5 | AI 模型名称 — 网关中已注册的名称 | AI_MODEL |
若必填项为空,安装将停止。 这是为了防止出现“看起来安装已完成但技术栈未启动”的状态而有意为之的行为。不会询问 DATABASE_URL —— PostgreSQL 随技术栈一起提供,安装会自动填充它。
不使用默认值而使用的七项 —— DATA_ROOT(/var/lib/pp-studio) · AI_PROVIDER(openai-compatible) ·
PP_LANG(en) · PP_TZ(Asia/Seoul) · APPS_PORT(5171) · REGISTRY(docker.kopens.io/ps) ·
PP_IMAGE_TAG(当前日历版本)。
如果填写了网关不提供服务的模型名称,就会和使用错误的密钥一样失败。因此从默认值中 移除,并作为询问项提出。
如需更改,可以通过环境变量指定,或使用 PP_ADVANCED=1 运行以询问所有项。
PS_ANTHROPIC_API_KEY 现在不再询问这是使用云端 Claude 时才需要的值,但由于该产品以网关为前提,实际上所有人都只是按回车
跳过的问项。功能保持不变,有三种方式输入 —— 安装时通过环境变量、
之后通过 bin/passwd.sh PS_ANTHROPIC_API_KEY(省略值则会通过提示符获取,不会留在命令行上)、
或者通过界面上的 设置 > AI。通过 PP_ADVANCED=1 也不会询问。
在同一台服务器上重新执行安装脚本,只会更新代码,.env 和本地备份(dist/)会被保留。
也可以直接用于升级。
可能是 CDN 缓存残留。请在 URL 后添加 ?v=$(date +%s) 重新下载。
如果提供了错误的值,将在安装前停止
在接触到机器之前——甚至在安装 Docker 之前——会使用提供的凭证实际调用一次。
平台使用 GET /api/v5/site?limit=1,网关使用 GET /v1/models。
只有“拒绝”才会停止。 “无法询问”不会停止。
| 响应 | 判定 | 安装 |
|---|---|---|
2xx | 已接受 | 继续 |
401 · 403 | 凭证错误 | 中止 |
400 | 安装脚本的请求错误 —— 产品缺陷,请告知我们 | 中止 |
5xx · 无法访问 | 无法判定 | 仅警告,继续 |
未将 5xx 与 401 放入同一列是有意为之 —— 曾发生过负载较高的平台返回 503,而在 3 分钟后
同一个令牌返回了 401 的情况。如果将正在巡检中或比 Studio 启动更晚的网关
误判为“错误密钥”,会导致本应成功的安装被拒绝。
也会同时检查模型名称。 读取网关的 /v1/models 响应,确认 AI_MODEL 是否在该列表中,
如果不存在,则打印出服务中的列表并停止。 如果无法读取列表,则不进行判定 ——
答案为空却声称“不存在”,无异于一项永远不会失败的检查那样的虚假结论。
PP_SKIP_CRED_CHECK=1这是用于在使用占位符凭证仅测试安装本身时使用的(产品的发布门禁使用此路径)。 在运维安装中启用此值,只是在安装时将首次使用时的失败向后推迟而已。
4. 安装(手动)
适用于已经下载了包或想要直接编写 .env 的情况。
cd /opt/kopens/plantpulse-studio-docker
sudo cp .env.example /etc/kopens/plantpulse-studio.env
sudo vi /etc/kopens/plantpulse-studio.env # 아래 표를 보고 값 채우기
sudo chmod 600 /etc/kopens/plantpulse-studio.env
bash bin/up.sh
/etc/kopens/plantpulse-studio.env环境变量文件不存放在安装目录内,而是放在 repo 树之外的
/etc/kopens/plantpulse-studio.env。权限为 0600。platform · ai · studio
三个产品遵循相同约定使用 /etc/kopens/plantpulse-<product>.env。
安装目录根目录下的 .env 是旧路径。compose 和其余脚本现在都不再读取该文件,
因此修改那里不会改变技术栈。现有安装的 .env 会被
bin/install.sh 移动到新路径(不会新建 —— 如果新建,数据库仍是旧密码,而 env 是新的默认值,会在下次重启时崩溃)。
环境变量主要项目
| 项目 | 说明 | 默认值 |
|---|---|---|
REGISTRY | 镜像仓库。清空则只使用本地镜像而不拉取(隔离网络) | docker.kopens.io/ps |
PP_IMAGE_TAG | 镜像标签。清空则跟随 VERSION 的日历版本。若需固定,建议使用快照标签(2026.09-20260911) | (空值) |
DATA_ROOT | 所有数据(工作区 · 构建 · 状态 · 数据库)的存储路径 | /var/lib/pp-studio |
PLATFORM_API_TARGET | 委托真实数据和认证的 PlantPulse 平台地址 | https://192.168.0.41 |
APPS_PORT | 应用监听器端口(预览 · 部署应用) | 5171 |
PP_LANG | Web 默认语言 ko / en | en |
PP_TZ | 时区(IANA ID)。 “今天 · 昨天 · 上周” 的解释依据 | Asia/Seoul |
STUDIO_CORS_ORIGINS | 仅在其他域调用 API 时指定。默认阻止 | 清空 |
DATABASE_URL | 外部 PostgreSQL 连接地址 —— 参考上文第 2 节 | 清空 (必填) |
PI_LLM_API_KEY · PP_API_TOKEN 等 | AI · 平台密钥 —— 参考密钥管理 | 清空 (必填) |
账户不通过环境变量传递。 当服务器没有任何账户时,会在数据库中植入引导管理员,之后在应用的 环境设置 → 用户管理中添加/删除账户并分配角色(管理员 / 构建者 / 查看者)。 请参阅下文 7. 首次登录。
PP_LANG=ko一行安装所生成的 .env 中没有 PP_LANG · PP_TZ 行,因此会应用默认值(en / Asia/Seoul)。
若要以韩文显示,请在 .env 中添加 PP_LANG=ko 并执行 bash bin/restart.sh。
.env 后,必须执行 bin/restart.shdocker restart 不会重新读取 .env。这就是值未生效却要长时间寻找“为什么没变”的典型陷阱。详细内容请参阅密钥管理。
5. 检查技术栈构成
安装完成后,应看到容器网络已启动。PostgreSQL 不在此处 —— 我们使用外部 PG。
| 容器 | 角色 |
|---|---|
plantpulse-studio-web | Studio UI(nginx :80) —— 静态界面 + API 代理 |
plantpulse-studio-server | 编排器(:5170) —— 代理 · 会话 · 部署 · 应用监听器(:5171) |
plantpulse-studio-agent-server | 构建器边车 —— 编写应用代码的编码引擎 |
plantpulse-studio-docker-proxy | Docker 守护进程通道。仅对 127.0.0.1 开放 |
docker.sock 不直接挂载到服务器,而是通过 Docker 代理进行访问。 创建和删除会话容器需要守护进程,
但直接给予套接字等同于拥有整个主机的权限。
只有代理不使用 host 网络,而是发布到 127.0.0.1:2375。如果使用 host 网络,
2375 端口将成为一个除了防火墙之外没有任何防护的开放守护进程。
要创建会话容器就需要 POST /containers/create,而能够调用它的一侧,也能够创建挂载了 / 的容器。
代理的控制单位是端点,而不是参数。
这个代理实际上只做两件事 —— 裁剪掉未被使用的 API 接口(卷 · 密钥 · 配置 · Swarm · 节点 · 插件 · 系统事件),以及将守护进程访问集中到一个点,使其可审计。 允许范围被缩小到 studio-server 实际使用的功能(容器 · 镜像 · 构建 · exec · 网络 · 仓库登录)。
因此,请将此技术栈置于信任边界之内。 应将创建应用的人视为对宿主机拥有 权限来进行运维。
此外,当用户打开项目时,应用会话容器会为每个项目启动一个。 它不是技术栈容器,而是服务器在需要时创建,并在空闲 30 分钟后回收。
6. 启动确认
cd /opt/kopens/plantpulse-studio-docker
bash bin/status.sh # 컨테이너 상태 + 헬스 + 세션 컨테이너 수
curl -s localhost:5170/health
安装完成后,建议立即运行一次综合巡检脚本。它会检查健康状态 · Web 响应 · 实际 登录 · 会话运行时镜像 · 容器状态,只要有一项失败,就会以错误结束。
bash bin/smoke-install.sh
✓ health
✓ client-config → {"lang":"ko",...}
✓ web 200
✓ 로그인(부트스트랩 계정)
✓ 세션 런타임 이미지
✓ 컨테이너 running(...)
✅ 설치 스모크 통과
应用会话容器使用 plantpulse-studio-runtime 镜像。当 bin/up.sh 在本地不存在时
会下载并打标签,但如果失败,会出现 ⚠️ 세션 런타임 이미지 없음 警告,并且打开项目会
失败。此时请检查仓库登录状态并重新执行 bash bin/up.sh。
如果本地已存在,up.sh 不会触碰它 —— 若想更换为新版本,
请参阅 bin/update.sh。
7. 首次登录
在浏览器中访问 http://<server-ip>/。
当服务器首次启动且没有任何账户时,会在数据库中植入引导管理员。
| 项目 | 值 |
|---|---|
| 用户名 | admin |
| 密码 | admin123! |
启动日志中也会显示 —— 부트스트랩 관리자 생성: admin — 로그인 후 비밀번호를 바꿀 것。
该值在所有安装中都是一样的。登录后立刻在环境设置 → 用户管理中更改 (密码重置,6 位以上)。修改环境变量文件不会更改 —— 服务器在登录时 按 ①数据库 → ②环境变量 的顺序检查,如果数据库中已有设置,则在此结束。
登录后需要做的事情:
- 环境设置 → 用户管理 — 更改引导管理员密码、创建现场用户账户、 分配角色(管理员 / 构建者 / 查看者)
- 更改密码 · API 密钥 — 使用
bin/passwd.sh一次性轮换数据库账户和 AI 密钥。在调试阶段仅需执行一次即可 - 环境设置 → AI — 检查 AI 提供商和密钥的连接状态
- 环境设置 → 平台 — 检查平台地址和密钥的连接状态(用于真实数据查询)
详细的界面说明请参见快速入门和 环境设置(管理员)。
8. 日常运维命令
所有命令均在安装目录(/opt/kopens/plantpulse-studio-docker)下执行。
bash bin/up.sh # 시작(레지스트리에서 최신 이미지 pull 포함). 종료 코드 0 = «준비됨»
bash bin/down.sh # 중지 — 데이터는 그대로 보존, 세션 컨테이너도 정리
bash bin/restart.sh # 재기동(.env 변경 반영)
bash bin/status.sh # 상태 요약
bash bin/logs.sh # 서버 로그 팔로우(기본 studio-server)
bash bin/logs.sh studio-web # 특정 서비스 로그
bash bin/update.sh # 이미지 갱신 + 재기동 → [업데이트](#9-更新)
bash bin/remove.sh # 컨테이너·네트워크 제거. **데이터는 보존이 기본**
start.sh · stop.sh 依然有效三个产品(Platform · AI · Studio)被统一使用相同的名称和含义的通用动词 ——
up · down · restart · status · logs · update · remove。
旧名称没有被删除。bin/start.sh 和 bin/stop.sh 继续执行相同的操作
(CI 会在远程主机上直接调用这些名称)。不需要一次性修改现有的运行手册。
down.sh 不仅仅调用 composeStudio 服务器在运行应用时创建的会话容器(plantpulse-studio=1 标签) 不由 compose 管理。
如果仅调用 docker compose down,这些容器会继续运行 ——
这就是“明明已停止,但容器还活着”的情况。down.sh 会一并清理它们。
remove.sh 不会删除数据 —— 若要删除,必须显式指定bash bin/remove.sh # 컨테이너·네트워크만. 데이터 그대로
bash bin/remove.sh --volumes # 데이터까지 (확인을 묻습니다)
bash bin/remove.sh --volumes --yes # 자동화용 — 묻지 않습니다
这个技术栈的真实数据不在命名卷中,而是在 DATA_ROOT 绑定挂载(默认
/var/lib/pp-studio)中 —— PG 数据 · 工作区 · 构建产物 · 状态。
使用 docker compose down -v 不会删除它们,但运维人员说“删除”时,往往也包含这些。
由于不可恢复,因此仅在明确请求时才处理。
要单独查看会话容器,
docker ps --filter label=plantpulse-studio=1
9. 更新
bin/update.sh 会重新拉取镜像并重启。重新执行安装脚本,运维脚本也会一起更新(.env · 备份会保留)。
=== "仅更新镜像"
cd /opt/kopens/plantpulse-studio-docker
bash bin/update.sh
up.sh(旧称 start.sh)会导致 «会话运行时» 保留旧镜像up.sh 会拉取 compose 服务的镜像。但是,用户应用实际运行的会话运行时镜像不是 compose 服务,因此不会被子 compose pull 处理,
而 up.sh 仅在该镜像本地不存在时才拉取 —— 如果已存在,则保持原样。
因此,如果只运行 up.sh,其他部分都是新镜像,但只有会话运行时在无声地保留旧版本。
update.sh 与 up.sh 的区别在于,它会强制重新拉取那一个镜像。
=== "更新到包"
curl -fsSL https://product.kopens.io/plantpulse-studio/install.sh | sudo bash
版本固定
版本号格式为 YYYY.MM(例如: 2026.08)。在不希望自动更新的运维环境中,
请在 .env 中固定标签。
TAG=2026.08
请先运行 bash bin/backup.sh。具体步骤请参阅备份与恢复。
镜像签名验证(可选)
可以确认部署的镜像是否由 KOPENS 签名。需要安装 cosign。
cd /opt/kopens/plantpulse-studio-docker
bash bin/verify-images.sh
[verify] ✅ docker.kopens.io/ps/plantpulse-studio-server:2026.08
[verify] ✅ docker.kopens.io/ps/plantpulse-studio-web:2026.08
[verify] ✅ docker.kopens.io/ps/plantpulse-studio-runtime:2026.08