Puter 部署实战指南:从本地开发到 Docker Compose 全栈自托管(基于官方 README 与仓库实现)
本文以 Puter 仓库中的多语言入门文档 README.es.md 为骨架,完整覆盖其中的本地开发、Docker 单容器、Docker Compose 与自托管四条上手路径,并结合仓库内的 tools/start.mjs、Dockerfile、docker-compose.yml 与 doc/self-hosting.md 等实现文件,补充每条路径背后的真实启动流程、配置键与首启细节。读完本文,你可以独立在本地跑起 Puter 开发环境,也可以在一台 Linux 主机上部署一套含数据库、缓存、KV、对象存储与反向代理的完整自托管栈。
Puter 是什么:五种典型用法
入口文档将 Puter 描述为“一个先进的、开源的、可自托管的互联网操作系统(Internet Computer)”,功能丰富、速度快、高度可扩展。按照 README.es.md 的说法,它可以被用作:
- 私有个人云:集中存放所有文件、应用与游戏,随时随地从任何设备访问;
- 发布平台:构建并发布网页、Web 应用与游戏;
- 云盘替代品:类似 Dropbox / Google Drive / OneDrive 的定位,但界面和功能取向不同;
- 远程桌面环境:面向服务器与工作站的浏览器内桌面;
- 开源学习项目:围绕 Web 开发、云计算与分布式系统构建的社区。
对开发者而言,仓库 README.md 进一步列出了平台提供的开发面:AI、云存储、键值数据库与 Serverless Workers,应用构建后可发布到其 App Store。仓库采用 AGPL-3.0 许可证(package.json 中 license 字段同为 AGPL-3.0-only),除非另有声明,仓库全部内容、子项目与模块均适用该协议;第三方库可能有各自许可。
系统要求
README.es.md 给出的系统要求如下:
| 项目 | 要求 |
|---|---|
| 操作系统 | Linux、macOS、Windows |
| 内存 | 最低 2GB(推荐 4GB) |
| 存储 | 1GB 可用空间 |
| Node.js | 文档写作时标注 16+(推荐 23+) |
| npm | 最新稳定版 |
需要注意一个以仓库为准的差异点:当前仓库的 package.json engines 字段声明了 "node": ">=24.0.0",且 Dockerfile 的构建与运行阶段均基于 node:24-slim。也就是说,从源码树本地运行 npm start 时,Node 24 是当前实际要求;西班牙语 README 中的 “16+/23+” 是较早版本留下的表述,建议以仓库清单为准。
路径一:本地开发(npm start)
入口文档给出的命令是:
git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start
启动后 Puter 运行在 http://puter.localhost:4100(若端口被占用则顺延到下一个可用端口)。
结合仓库源码看,npm start 实际执行的是 tools/start.mjs(由 package.json 的 "start": "node ./tools/start.mjs" 绑定)。在默认模式下它依次做三件事(见 tools/start.mjs):
npm run setupExtensions— 执行 tools/extensionSetup.mjs 准备扩展;npm run build:ts— 用tsc -p tsconfig.build.json编译后端 TypeScript,再由 tools/write-dist-package-json.mjs 写出 dist 的 package.json;- 以
--enable-source-maps启动编译产物,并预加载./dist/src/backend/telemetry.js,最终入口是./dist/src/backend/index.js。
此外,tools/start.mjs 还支持两个对开发者很有用的模式(这是入口文档没有展开的实现细节):
npm start --server=puter.com:跳过本地后端,仅在本机用src/gui/dev-server.js起 GUI,对接远程 Puter 后端。裸域名会被解析为https://api.<domain>,完整 origin 则原样使用;--extensions=<dir>[;<dir>...]:把仓库外的 GUI 扩展目录打进本地服务(多个目录用;分隔),等价于设置PUTER_GUI_EXTENSION_PATHS。相对路径基于执行npm start的目录(INIT_CWD)解析。
入口文档提示:如果 npm start 跑不起来,可查阅自托管排障文档;当前仓库中对应的自托管说明位于 doc/self-hosting.md。
路径二:Docker 单容器
入口文档给出的单容器命令(一条式):
mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter
同样会得到 http://puter.localhost:4100。这条命令的两个挂载点与 Dockerfile 严格对应,值得从镜像构建层面理解:
/etc/puter是配置注入点。Dockerfile 注释说明:自托管者把config.json挂载到/etc/puter/config.json,v2 配置加载器会将其深度合并到内置的config.default.json之上,因此部分覆盖(partial override)即可,文件不存在则全部走默认值。运行时由PUTER_CONFIG_PATH=/etc/puter/config.json指定(Dockerfile)。/var/puter是持久数据目录,对应配置中所有指向/var/puter的运行时状态。- 镜像以非 root 用户运行(
USER node),预建/etc/puter与/var/puter并归属node:node,这就是命令里sudo chown -R 1000:1000的原因——让宿主机目录对 UID 1000 可写。 - 镜像
EXPOSE 4100,内置HEALTHCHECK每 30 秒对容器内/test端点做wget --spider探测(Dockerfile)。 - 运行阶段是
node:24-slim瘦身镜像,不含构建工具链;构建阶段编译后端 TS,并并行构建 GUI 与 puter-js 的 webpack 产物(Dockerfile),生成的/dist/bundle.min.{js,css}与/sdk/puter.js在 CDN 键未配置时作为本地静态资源兜底。 - 容器入口命令为
node -r ./dist/src/backend/telemetry.js ./dist/src/backend/index.js(Dockerfile),与本地npm start的最终启动方式一致。
路径三:Docker Compose 全栈
Linux / macOS
入口文档给出的快速流程:
mkdir -p puter/config puter/data
sudo chown -R 1000:1000 puter
wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml
docker compose up
Windows (PowerShell)
mkdir -p puter
cd puter
New-Item -Path "puter\config" -ItemType Directory -Force
New-Item -Path "puter\data" -ItemType Directory -Force
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml"
docker compose up
当前仓库的 compose 实际上是一套完整生产栈
需要说明的是,当前仓库的 docker-compose.yml 已演进为一套完整自托管栈,拉起 Puter 及其依赖的全部外部服务。按 doc/self-hosting.md 的表格整理:
| 容器 | 镜像 | 角色 |
|---|---|---|
puter-caddy |
caddy:2.11-alpine |
80/443 反向代理,转发到 Puter(docker-compose.yml) |
puter |
ghcr.io/heyputer/puter |
应用本体,监听 4100,仅对内暴露 |
puter-mariadb |
mariadb:11 |
SQL 数据库,首启自动应用 schema |
puter-valkey |
valkey/valkey:8-alpine |
Redis 兼容缓存 + 限流后端 |
puter-dynamo |
amazon/dynamodb-local |
KV 存储,表在首启自动创建 |
puter-s3 |
rustfs/rustfs |
S3 兼容对象存储(文件注释给出 MinIO 替换方式) |
puter-s3-init |
amazon/aws-cli |
一次性容器,首启创建 puter-local bucket 后退出 |
可选服务(compose profile ai,按需启用):
| 容器 | 镜像 | 角色 |
|---|---|---|
puter-ollama |
ollama/ollama |
本地 LLM(CPU;GPU 直通可选) |
puter-ollama-init |
ollama/ollama |
一次性容器,首启拉取默认模型 tinyllama |
几个与源码可互相印证的关键设计:
- Valkey 以单节点 cluster 模式运行。docker-compose.yml 的注释解释:Puter 的 ioredis 客户端只说 Cluster 协议,所以首启时把全部 16384 个槽位分配给自己(
CLUSTER ADDSLOTSRANGE 0 16383),后续启动检测到nodes.conf已有槽位即跳过;--cluster-require-full-coverage no保证即使出现部分槽位,读操作仍可用。这与 config.template.jsonc 中redis.startupNodes的注释“单容器请跑 cluster 模式(单节点、全槽位)”一致。 - 依赖编排基于健康检查。
puter服务声明depends_on等待 valkey/mariadb 达到service_healthy、dynamoservice_started、s3-initservice_completed_successfully(docker-compose.yml);mariadb 的健康检查用healthcheck.sh --connect --innodb_initialized确认不仅监听端口、而且已接受认证。 - DynamoDB 表由 Puter 自举。
dynamo.bootstrapTables = true时 Puter 启动时创建store-kv-v1表(docker-compose.yml 注释);该开关只对本地模拟器使用,指向真实 AWS 时应通过 IaC 建表(config.template.jsonc 对同一事项有相同的“NEVER set against real AWS”警告)。 - Ollama 藏在
aiprofile 后。不带--profile ai时两个 ollama 容器完全不起;同时要求config.json里写"providers": { "ollama": { "enabled": false } },否则 Puter 会反复探测127.0.0.1:11434并在每次启动打印ECONNREFUSED(docker-compose.yml 注释与 doc/self-hosting.md 的说明一致)。启用时用docker compose --profile ai up -d,模型默认tinyllama(约 640 MB 磁盘 / 700 MB 内存),可用OLLAMA_DEFAULT_MODEL替换;NVIDIA GPU 直通需宿主机安装 nvidia-container-toolkit 并解开deploy:块。 - 状态目录集中在
./puter/data/<service>/,一处备份即可;z挂载后缀是为 Fedora/RHEL 的 SELinux 重标注(其他发行版上是 no-op),缺失时容器会循环EACCES(docker-compose.yml 注释)。
更省事的入口:一键安装脚本
doc/self-hosting.md 推荐的其实是一行安装命令,其实现是仓库根目录的 install.sh。它的行为顺序在脚本头注释中写得很清楚(install.sh):
- 检查
docker(含 compose 插件)、curl、openssl; - 创建
./puter-selfhosted/(可用PUTER_DIR覆盖),并预建puter/config、puter/data/*、puter/tls,数据目录chmod 0777以规避各镜像非 root UID 差异导致的挂载写权限问题(install.sh); - 从 OSS 仓库下载
docker-compose.yml与caddy/Caddyfile(Caddyfile 缺失时 Docker 会把它当成目录自动创建,导致 “not a directory” 挂载失败,脚本对此做了清理); - 用
openssl rand -hex生成一整套密钥(MARIADB_ROOT_PASSWORD、MARIADB_PASSWORD、S3_SECRET_KEY、JWT_SECRET、JWT_SECRET_V2、URL_SIGNATURE_SECRET),写入.env与puter/config/config.json; docker compose up -d,并提示从 puter 容器日志中提取首启管理密码。
可调环境变量(install.sh):
| 变量 | 默认值 | 说明 |
|---|---|---|
PUTER_DIR |
./puter-selfhosted |
安装目录 |
PUTER_URL |
GitHub raw(main 分支) | compose 文件来源 |
PUTER_DOMAIN |
puter.localhost |
服务域名 |
PUTER_PORT |
80 |
Caddy HTTP 端口 |
PUTER_PROTOCOL |
http |
公网协议;TLS 在 Puter 前终结时设为 https |
PUTER_TRUST_PROXY |
1 |
前置反代跳数(1=Caddy 单跳,2=CF→Caddy→Puter) |
PUTER_ENV |
prod |
prod 或 dev |
PUTER_FORCE |
0 |
置 1 才会覆盖已有 .env/config.json |
重复运行是安全的:已存在的 .env/config.json 不会被覆盖(install.sh)。另外脚本会检查:若 PUTER_PROTOCOL=https 但 ./puter/tls/fullchain.pem 缺失,会警告此时 Caddy 仍只提供 HTTP(install.sh)。
首启、登录与验证
docker compose up -d 之后首启约需 30 秒:MariaDB 完成初始化,Puter 应用 schema 与默认应用。观察方式:
docker compose logs -f puter
doc/self-hosting.md 给出健康启动日志样例:
[config] override from /etc/puter/config.json
[mysql] running migrations from /opt/puter/dist/src/backend/clients/database/migrations/mysql: 2 file(s)
[mysql] applied mysql_mig_1.sql (...)
[mysql] applied mysql_mig_2.sql (9 statements)
首启后管理员登录用户为 admin,临时密码只会在 puter 容器日志中打印一次:
docker compose logs puter | grep tmp_password
登录后在设置中修改密码。migrationPaths 指向的迁移文件是幂等的,跨版本升级重启可安全重放;数据卷在 docker compose down 后保留(docker compose down && rm -rf puter/data 才是不可逆的彻底重置)。
关键配置项:config.json 怎么选
配置模板见 config.template.jsonc(每个字段只存在于唯一规范键,无 fallback 别名),逐键的源码级文档在 src/backend/types.ts。自托管场景中最容易踩坑的几个键,doc/self-hosting.md 给出了完整论证,这里按重要性归纳:
jwt_secret_v2:Puter 签名与校验认证 token 的 HMAC 密钥(JWT 头kid: 'v2')。v1 旧格式已退役——用旧jwt_secret签发的 token 不再能通过校验,持有者需要重新登录;从旧版本升级时旧jwt_secret键会被忽略,可直接删除。env: "prod":内置config.default.json出厂为env: "dev"(配合源码树的 webpack-dev-server 工作流)。Docker/自托管跑的是预构建静态包,必须设prod,否则首页会等待一个不存在的 CSS manifest。database.migrationPaths:首启自动应用内置 MySQL/MariaDB schema,幂等,跨重启保留即可。dynamo.aws是 snake_case(access_key/secret_key),与 S3 块的 camelCase(accessKeyId/secretAccessKey)不通用;对 dynamodb-local 写占位值即可,AWS SDK 只是要求“有值”。写错大小写会得到Error: DynamoDB aws config requires both access_key and secret_key。meteringEnforcement.subscriptions: false:Puter 对部分界面(OpenAI/Anthropic 兼容的 AI 端点)声明“仅付费计划”。自托管没有付费计划,所有账户都落在免费策略上,若不关闭计划门,这些路由会对所有人返回402 subscription_required。更彻底的做法是"unlimitedMetering": true:所有账户解析为不限额策略,用量仍被记录,但永远不会因预算不足被拒(config.template.jsonc 对两者的语义有完整说明)。s3.s3Config.forcePathStyle: true:RustFS / MinIO 需要 path-style URL(<endpoint>/<bucket>);换成真实 AWS S3 时应去掉该开关(虚拟主机模式),且publicEndpoint可整体省略。s3.s3Config.publicEndpoint:endpoint(如http://s3:9000)只在 docker 网络内可解析,而下发给浏览器的预签名上传/下载 URL 需要主机可达地址。Caddy 把s3.<domain>子域内部路由到 RustFS 并端到端保留 Host 头(S3 签名校验的要求),因此浏览器无需暴露独立端口、TLS 后也不会有混合内容。启用 TLS 后应改为https://s3.<your-domain>。trust_proxy:Caddy 终结 TLS 并转发X-Forwarded-For。不设它,req.ip就是 Caddy 容器的 docker 网络地址,限流与 IP 审计日志全部失真。取值为可信跳数(1=Caddy 单跳,前置 Cloudflare 则 2);绝不要设true(信任所有跳,使 XFF 可伪造)——config.template.jsonc 对此有同样警告。
TLS 与反向代理要点
仓库自带 caddy/Caddyfile,其设计目标是“镜像生产 ALB 的行为”:
- 接受任意 Host 头,把子域路由(
api.*、site.*、app.*、dev.*及用户动态子域)全部交给 Puter 内部处理; auto_https off(caddy/Caddyfile):Puter 在运行时为用户发明形如<name>.site.<domain>的子域,只有 DNS-01 通配符证书能覆盖,而标准caddy:2.11-alpine镜像不带 DNS provider 插件,因此证书由运维者提供(通配符fullchain.pem+privkey.pem放入./puter/tls/);s3.前缀的 Host 单独reverse_proxy s3:9000,其余全部转发puter:4100,且flush_interval -1无缓冲流式转发(Puter 使用 SSE 与 socket.io;WebSocket 升级由 Caddy 默认代理);请求体上限1024MiB与生产 ALB 默认一致(Puter 对大文件做分块上传)。
若你已有一套自己的边缘代理(Traefik、nginx、HAProxy、云 LB),doc/self-hosting.md 的“Running behind your own reverse proxy”一节给出六条硬性规则,任何一条出错都会表现为重定向循环或 Invalid Host header:不改写 Host;外部域名必须等于 config.json 的 domain;代理终结 TLS 时 protocol 必须设为 https;转发 Host/X-Forwarded-Proto/X-Forwarded-For/Upgrade+Connection(漏掉 WebSocket 升级头会导致实时连接静默失败);trust_proxy 等于代理跳数;把 *.<domain> 与 *.site.<domain> 的泛解析路由给 Puter。
DNS 侧需要为主域加 api.*、site.*、app.*、dev.*、s3.* 的通配符记录;dig 验证解析生效通常需要 5–60 分钟。
运行中的管理与常见故障
日常管理命令(来自 doc/self-hosting.md):
# 升级
docker compose pull
docker compose up -d
# 日志
docker compose logs -f puter
# 停止但保留数据
docker compose down
常见故障与对应原因:
- Caddy 返回 502 / Bad Gateway:puter 容器没起来,
docker compose logs puter通常指向.env与config.json之间的数据库密码不一致(两者必须来自同一次密钥生成,漂移会触发ER_ACCESS_DENIED_ERROR); - 登录页提示 “admin password not set”:首启临时密码只打印一次,用
docker compose logs puter | grep tmp_password找回; - 健康检查报 unhealthy 但站点正常:容器内健康检查固定打
puter.localhost:4100/test,改了 domain/port 后检查项仍用默认值,站点本身无碍; compose up卡在 “waiting for service to be healthy”:docker compose ps定位不健康的容器;MariaDB 冷启约 20–30 秒,其余服务均应在 5 秒内就绪。
支持渠道与许可证
入口文档与支持章节一致:Bug 或功能请求请开 issue;社区渠道包括 Discord、X (Twitter)、Reddit、Mastodon;安全问题联系 security@puter.com;一般邮件联系 hi@puter.com。
许可证方面,本仓库(含全部内容、子项目、模块与组件)遵循 AGPL-3.0,除非明确另作说明;仓库内第三方库可能受其自身许可约束。
多语言文档
Puter 的入门 README 维护了 30 余种语言版本,统一放在 doc/i18n/ 目录下,与根目录英文 README.md 并列,例如中文 README.zh.md、西班牙语 README.es.md、法语 README.fr.md、德语 README.de.md、日语 README.jp.md、俄语 README.ru.md、阿拉伯语 README.ar.md 等。各语言版内容随主 README 演进,但细节(如 Node 版本要求)可能与仓库当前清单存在时间差,以 package.json 与 doc/self-hosting.md 为准。
小结
按本文路径走一遍,你可以在本地用三条命令进入开发模式(git clone → npm install → npm start,入口 tools/start.mjs),也可以用 install.sh 一条命令在单主机上拉起含 MariaDB、Valkey(cluster 模式)、DynamoDB-local、RustFS S3 与 Caddy 的完整栈,首启约 30 秒后通过 docker compose logs puter | grep tmp_password 拿到管理员密码。配置面则以 puter/config/config.json 为唯一注入点(深度合并于内置默认值之上),密钥、env: "prod"、trust_proxy、S3 path-style 与计量开关这几项是自托管中最值得逐项核对的部分。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00