资讯动态

Archon 云部署排错实录:Docker Compose 中 bcrypt 哈希的 `$` 转义与表单认证(Form Auth)修复指南

发布时间:2026/9/13 5:34:25 来源:尧图企业网站定制
Archon 云部署排错实录Docker Compose 中 bcrypt 哈希的$转义与表单认证Form Auth修复指南【免费下载链接】ArchonThe first open-source harness builder for AI coding. Make AI coding deterministic and repeatable.项目地址: https://gitcode.com/GitHub_Trending/archon3/Archon本文基于 Archon 仓库内 issue #1168 的完整调查记录见 .claude/PRPs/issues/completed/issue-1168.md深入剖析一个典型的云部署陷阱docker-compose.yml的env_file机制会对.env中的值做变量插值导致表单认证Form Auth使用的 bcrypt 哈希因未转义$而失效。读完本文你将掌握 Docker Compose 中$的正确转义规则、auth-service表单认证的完整部署路径以及如何用 grep 等手段验证文档与配置的一致性避免同类静默故障。调查结论快照一个小而致命的文档问题issue #1168 是一份针对改进云部署文档的专项调查Type: DOCUMENTATION其结论如下指标结论理由优先级PriorityLOWVPS 部署指南主体已相当完整仅一处错误的认证示例会导致局部的部署失败复杂度ComplexityLOW只涉及一个文档文件和一个示例无任何运行时集成改动置信度ConfidenceHIGH问题可从未转义的$示例复现且与已正确转义的.env.example指引直接矛盾这个分级很有代表性它不是一个功能缺陷而是一个能静默破坏认证链路的文档缺陷——按错误示例操作的用户服务照常启动但登录永远无法成功。问题陈述表单认证示例里的未转义 bcrypt 哈希云 VPS 部署指南packages/docs-web/src/content/docs/deployment/cloud.md已经提供了完整的 Docker Compose 手动部署路径并明确要求运维人员直接编辑仓库的.env而不是运行archon setup向导。但在packages/docs-web/src/content/docs/deployment/docker.md的 Docker 表单认证Form Auth走查中示例仍然写出了这样的配置AUTH_PASSWORD_HASH$2b$12$REPLACE_WITH_YOUR_HASH而 Docker Compose 会对.env文件中的值执行变量插值——$...被当作插值语法处理。也就是说照着这个示例操作认证会在启动阶段被静默破坏。根因分析Docker Compose 的$插值机制为什么$2b$12$REPLACE_WITH_YOUR_HASH会坏掉bcrypt 哈希的格式为$2b$12$22位salt31位hash其中$2b$表示算法版本、$12$表示 cost 因子即 2^12 轮计算。整串哈希中散布着多个$字符。当 Docker Compose 通过env_file: .env把该值注入auth-service容器时以$开头且后随合法变量名的片段例如$REPLACE_WITH_YOUR_HASH会被当作环境变量引用替换为对应值通常为空即使只是前缀片段整个插值解析过程也可能吞掉或改写部分$结构。最终AUTH_PASSWORD_HASH拿到的是一串被篡改的字符串auth-service在启动时就会校验失败。源码级佐证auth-service 的启动校验仓库中的 auth-service/server.js 是表单认证的实际实现它在启动阶段就做了严格校验const PASSWORD_HASH process.env.AUTH_PASSWORD_HASH ?? ; // ... if (!USERNAME || !PASSWORD_HASH || !COOKIE_SECRET) { console.error( [auth-service] Missing required env vars: AUTH_USERNAME, AUTH_PASSWORD_HASH, COOKIE_SECRET ); process.exit(1); } try { bcrypt.getRounds(PASSWORD_HASH); // 校验是否合法的 bcrypt 哈希 } catch { console.error([auth-service] AUTH_PASSWORD_HASH is not a valid bcrypt hash. ...); process.exit(1); }bcrypt.getRounds()会解析哈希前缀一旦哈希被 Compose 插值篡改例如$REPLACE_WITH_YOUR_HASH段被替换为空getRounds抛错容器直接exit(1)。故障表现为容器不断重启 登录页 502而非直观的密码错误排查起来极具迷惑性。证据链Evidence ChainWHY用户按文档走查操作时表单认证会失败BECAUSE文档中的 bcrypt 哈希包含单个$字符证据packages/docs-web/src/content/docs/deployment/docker.md中表单认证示例对应修复前的 349-355 行BECAUSEDocker Compose 在把环境值传入容器前会先做$插值证据同一页面 Basic Auth 示例对应 307-311 行与 .env.example对应 271-274 行均使用$$转义并给出了插值警告ROOT CAUSE表单认证示例缺少转义的$$也缺少显式警告说明。修复方案三步走Step 1澄清 Docker Compose 配置路径cloud 指南在 packages/docs-web/src/content/docs/deployment/cloud.md 中加入醒目标注本指南针对仓库的 Docker Compose 部署——运维人员应直接编辑/opt/archon/.env不要在 VPS 上运行archon setup。原因是该向导写入的是 Archon 自己管理的 CLI 环境作用域而不是 Compose 实际消费的仓库.env文件两者互不相通混用会导致配置写进去了却不生效。这一条对任何使用 Compose 部署的项目都通用要认清配置的真正消费方。docker-compose.yml中的auth-service通过env_file: .env读取配置改动必须落在该文件上。Step 2修正表单认证的环境变量示例将AUTH_PASSWORD_HASH$2b$12$REPLACE_WITH_YOUR_HASH改为AUTH_PASSWORD_HASH$$2b$$12$$REPLACE_WITH_YOUR_HASH并紧跟一句说明bcrypt 哈希中的每一个$都必须写成$$因为 Docker Compose 会执行变量插值。修复后的完整表单认证部署流程当前 docker.md 与 cloud.md 中的规范示例如下1. 生成 bcrypt 密码哈希首次运行会构建 auth-service 镜像输出的哈希以$2b$12$...开头docker compose --profile auth run --rm auth-service \ node -e require(bcryptjs).hash(YOUR_PASSWORD, 12).then(h console.log(h))2. 生成随机的 Cookie 签名密钥docker run --rm node:22-alpine \ node -e console.log(require(crypto).randomBytes(32).toString(hex))3. 在.env中写入以下三项AUTH_USERNAMEadmin AUTH_PASSWORD_HASH$$2b$$12$$REPLACE_WITH_YOUR_HASH COOKIE_SECRETREPLACE_WITH_64_HEX_CHARS务必转义每个$$$2b$$12$$REPLACE_WITH_YOUR_HASH中的每一处$都写成了$$否则 Compose 会将其当作变量插值处理。4. 更新 Caddyfile若尚未创建先cp Caddyfile.example Caddyfile取消注释Option A 表单认证块handle /login、handle /logout、handle { forward_auth ... }三块注释掉默认的 No authhandle块site 块底部最后一个handle { ... }。对应 Caddyfile.example 中的结构# handle /login { # reverse_proxy auth-service:{$AUTH_SERVICE_PORT:9000} # } # handle /logout { # reverse_proxy auth-service:{$AUTH_SERVICE_PORT:9000} # } # handle { # forward_auth auth-service:{$AUTH_SERVICE_PORT:9000} { # uri /verify # copy_headers X-Auth-User # } # sse path /api/stream/* # reverse_proxy sse app:{$PORT:3000} { # flush_interval -1 # } # reverse_proxy app:{$PORT:3000}5. 以 cloud auth 两个 profile 启动使用本地 PostgreSQL 时再加--profile with-dbdocker compose --profile with-db --profile cloud --profile auth up -d6. 访问你的域名应被重定向到/login。登出访问/logout清除会话 Cookie 并回到登录页。会话时长默认 24 小时COOKIE_MAX_AGE86400可在.env中覆盖COOKIE_MAX_AGE3600 # 1 hour重要提示表单认证与 Basic Auth不可同时启用二选一——要么保持CADDY_BASIC_AUTH为空要么从 Caddyfile 中移除 basic auth 的protected块。Step 3校验文档一致性确认更新后的示例与 .env.example、Caddyfile.example 以及 Basic Auth 章节的转义写法保持一致。仓库当前的证据显示根目录 .env.example 第 271-274 行已使用$$写法AUTH_PASSWORD_HASH$$2b$$12$$REPLACE_WITH_BCRYPT_HASH并附有插值警告docker.md 第 353 行与 cloud.md 第 527 行均已更新为$$2b$$12$$REPLACE_WITH_YOUR_HASH并注明转义每一个$packages/docs-web/src/content/docs/reference/configuration.md 的配置表明确标注AUTH_PASSWORD_HASH—— Bcrypt hash for form-based auth password (escape$as$$in Compose)。⚠️ 需要特别留意的例外仓库中的 deploy/.env.example第 73 行附近仍保留着AUTH_PASSWORD_HASH$2b$12$REPLACE_WITH_HASH的单$注释示例。若将其直接复制为/opt/archon/.env会原样复现本问题。一切以根目录.env.example的$$写法为准。需要遵循的既有模式Basic Auth 的$$转义表单认证的修复并非凭空发明仓库中 Basic Auth 路径早已给出了正确范式。docker.md的 Basic Auth 章节对应 307-311 行示例CADDY_BASIC_AUTHbasicauth protected { admin $$2a$$14$$abc123... }配套操作流程为# 1. 用 Caddy 官方镜像生成 bcrypt 哈希切勿在 .env 里放明文密码 docker run caddy caddy hash-password --plaintext YOUR_PASSWORD # 2. 写入 .env注意 $$ 转义 # CADDY_BASIC_AUTHbasicauth protected { admin $$2a$$14$$abc123... } # 3. 重启 Caddy docker compose --profile cloud restart caddy同样deploy/cloud-init.yml与 Caddyfile.example 中的注释示例也都采用$$2a$$14$$hash写法。凡是经过 Compose 注入的 bcrypt 值一律$变$$这是整个仓库的一致约定。两种认证方式的选型参考维度表单认证Form AuthBasic Auth交互形态深色主题 HTML 登录页浏览器原生凭据弹窗会话能力24 小时会话 Cookie、支持登出每次请求携带凭据额外容器需要auth-service边车容器零额外容器最简转义要求AUTH_PASSWORD_HASH中每个$写$$CADDY_BASIC_AUTH中每个$写$$另外需要说明PostgreSQL 部署推荐优先使用 Better Auth 的原生 Web UI 登录BETTER_AUTH_SECRET它取代单用户的auth-service边车提供真实的按用户账户体系自注册默认关闭通过ARCHON_AUTH_ALLOWED_EMAILS白名单邀请成员。该边车在 SQLite / 单机安装场景下仍完全可用。边界情况与风险缓解风险 / 边界情况缓解措施用户复制的哈希中包含更多$段不止前缀明确告知用户转义每一个$而非只转义前缀把完整的 Docker 指南复制进 cloud 文档造成双份维护漂移保持修复范围最小化保留原有交叉链接Docker 参考只维护一份这里的核心原则值得推广到任何文档工程示例必须与机制一致。既然 Compose 会插值所有示例就都必须转义既然要转义就必须在示例旁用一句话把为什么讲清楚否则下一个维护者还会踩同一坑。验证方法仓库级校验命令bun run format:check bun run lint人工验证grep 表单认证示例确认 bcrypt 哈希的每一个$段都写成了$$且示例旁包含插值警告说明grep -n AUTH_PASSWORD_HASH .env.example packages/docs-web/src/content/docs/deployment/docker.md packages/docs-web/src/content/docs/deployment/cloud.md正确状态下.env.example与两份部署文档中的AUTH_PASSWORD_HASH应全部呈现$$2b$$12$$...形态。范围边界Scope BoundariesIN SCOPE澄清 cloud 指南中的 Docker Compose 环境文件路径修正 Docker 表单认证文档示例并解释 Compose 转义规则。OUT OF SCOPE运行时认证逻辑改动、CLIsetup行为改动、把 Docker 指南复制进 cloud 页面、以及任何与部署无关的重构。仓库佐证索引调查记录本体.claude/PRPs/issues/completed/issue-1168.mdDocker 部署指南表单认证示例已修复packages/docs-web/src/content/docs/deployment/docker.md云 VPS 部署指南含 Compose 路径澄清与表单认证packages/docs-web/src/content/docs/deployment/cloud.md环境变量模板$$转义权威写法.env.exampleCaddy 反向代理模板Option A 表单认证块Caddyfile.exampleCompose 服务编排auth-serviceprofile 定义docker-compose.yml表单认证运行时实现与启动校验auth-service/server.js云初始化脚本自动化部署路径deploy/cloud-init.yml配置项参考表AUTH_PASSWORD_HASH转义说明packages/docs-web/src/content/docs/reference/configuration.md安全参考SQLite/单机与 Postgres 的认证取舍packages/docs-web/src/content/docs/reference/security.md结语文档也是部署链路的一部分issue #1168 的修复看似只是把$改成$$背后却是文档示例即代码的工程原则在 Docker Compose 这类存在隐式值变换插值、转义、默认值展开的系统中任何未经验证的示例都可能成为生产故障的入口。本次调查通过证据链现象 → 机制 → 根因逐层定位用auth-service的启动校验代码验证了故障模式并最终在文档层完成收敛。下次你在.env中粘贴任何含$的密钥、哈希或令牌时请先问一句Compose 会怎么解释它【免费下载链接】ArchonThe first open-source harness builder for AI coding. Make AI coding deterministic and repeatable.项目地址: https://gitcode.com/GitHub_Trending/archon3/Archon创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价