Puter 自托管在反向代理后出现重定向循环和 Invalid Host header 怎么排查?
【免费下载链接】puter🌐 The Internet Computer! Free, Open-Source, and Self-Hostable.项目地址: https://gitcode.com/GitHub_Trending/pu/puter
如果你用docker-compose.yml自托管了 Puter,并且没有用自带的puter-caddy,而是把自己的反向代理(Traefik、nginx、HAProxy、云负载均衡、另一个 Caddy 等)放在前面,浏览器里最常见的两种故障就是:重定向循环(页面不停跳转)和Invalid Host header报错。
doc/self-hosting.md 明确说明,这两个症状指向同一组原因:代理转发规则配错了。Puter 在任何部署方式下都不自己终结 TLS,并且完全靠Host头做子域路由——api.<domain>、site.<domain>、app.<domain>都靠传入的 Host 区分。排查就按下面六个检查项顺序走,每一项都对应文档中列出的"the rules that actually matter"。
前提:确认你的拓扑属于哪一种
文档支持两种接法,后续检查项对两者都适用:
- 保留自带的 Caddy作为你的代理直接对话的单一跳,你的代理只对接
puter-caddy; - 绕过 Caddy,把流量直接转发到
puter容器的4100端口——在 docker-compose.yml 的puter服务下取消4100:4100端口映射的注释(或让你的代理加入 compose 网络)。
两种方式都可以,关键是下面的规则。改完任何一项后,用docker compose restart puter让配置生效。
检查项 1:Host 头是否被改写了
Puter 完全基于 Host 路由。代理必须原样转发外部请求的 Host:
- 不要把外部域名重写成内部名(比如
puter.local)。文档指出这样做会迫使你把每个子域手工重新映射,而且仍然会破坏 signed-URL 和 CORS 校验。 - 大多数代理默认保留 Host,问题通常出在你主动 override 了它。检查代理配置里是否有
proxy_set_header Host、host_rewrite之类的规则。
检查项 2:外部域名必须与 config.json 的domain一致
这是Invalid Host header的直接来源——Puter 会拒绝它不认识的主机名,报的就是Invalid Host header。
核对puter/config/config.json:
- 如果用户从
puter.example.com访问这台机器,domain就必须是puter.example.com; - hosting 相关域必须是它的真实子域:
static_hosting_domain=site.puter.example.com、private_app_hosting_domain=app.puter.example.com等,与安装脚本/config.json的默认布局一致(site.*、host.*、app.*、dev.*)。
相关字段可对照 config.template.jsonc:domain、static_hosting_domain、static_hosting_domain_alt、private_app_hosting_domain、private_app_hosting_domain_alt。模板里还有allow_all_host_values(默认true)、allow_no_host_header、enable_ip_validation等 Host 处理开关,模板注释说明这些是 dev-friendly 的默认值,公共部署应收紧。
检查项 3:protocol是否与对外协议一致
这是重定向循环最常见的根因。protocol必须匹配对外(浏览器看到的)scheme:
- 代理终结 TLS 时,
config.json里必须是"protocol": "https"(用安装脚本部署则为PUTER_PROTOCOL=https),同时pub_port改为443; - 把
s3.s3Config.publicEndpoint一并更新为https://s3.<你的域名>(doc/self-hosting.md 中 Step 3 给出的示例形如"publicEndpoint": "https://s3.puter.local",替换成你的实际域名)。
原因:Puter 用它来构造 origin、重定向、signed S3 URL 和 OIDC 回调 URL。在 HTTPS 代理后面把protocol留在http,文档明确会看到重定向循环、登录失败和 mixed-content 错误。
{ "protocol": "https", "pub_port": 443 }检查项 4:标准代理头是否都转发了
Puter 需要代理转发这四个头:
| 头 | 用途 |
|---|---|
Host | 原始请求 Host,不重写(见检查项 1) |
X-Forwarded-Proto | 外部scheme(https),让 Puter 知道 TLS 在上游已终结 |
X-Forwarded-For | 真实客户端 IP(限流 + 审计日志) |
Upgrade/Connection | WebSocket / socket.io 升级必须透传,否则实时连接会静默失败 |
自带的 Caddy 就是按这个约定工作的:caddy/Caddyfile 注释说明它转发时附加X-Forwarded-For/-Proto/-Host,并且这正是trust_proxy所数的那些跳;SSE / socket.io 场景下它用flush_interval -1做无缓冲转发。你自己的代理要达到同样效果。
检查项 5:trust_proxy是否等于代理跳数
trust_proxy要设为客户端到 Puter 之间的代理数量,保留自带 Caddy 时把 Caddy 也算进去:
- 一个外部代理直接对接 Puter →
"trust_proxy": 1(安装脚本为PUTER_TRUST_PROXY=1); - 前面还有一层(例如 Cloudflare → 你的代理 → Puter)→
2。
配置错误的后果文档也写清了:设太小,req.ip会变成代理的地址,限流失效;永远不要设为true——它会信任每一跳,使X-Forwarded-For可伪造。config.template.jsonc 中该键的默认值是false(safe default),自托管示例配置里用的是1。
检查项 6:通配符路由和 DNS 是否覆盖所有子域
你的代理必须把这些流量都交给 Puter,且 Host 保持完整(Puter 内部按子域路由,代理只需原样转发):
*.<domain>——覆盖api.*、app.*和s3.<domain>(浏览器做 signed-URL 上传/下载时访问它);*.site.<domain>以及其他 hosting 域。
DNS 侧要有通配记录。文档给出的验证命令:
dig puter.example.com dig api.puter.example.com两条都应返回你的服务器 IP;不返回的话按文档说法是 DNS 传播慢,等 5–60 分钟。
应用修改并验证结果
改完puter/config/config.json(以及代理配置)后:
docker compose restart puter docker compose logs -f puter文档给出的健康启动日志示例(示例结果,实际输出的迁移文件名和语句数可能不同):
[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)然后打开https://<你的域名>(没开 TLS 则用http://)。登录账号是admin,临时密码只在首次启动时打印一次:
docker compose logs puter | grep tmp_password能打开页面、不再循环跳转、请求api.<domain>等子域不再出现Invalid Host header,说明这组规则已经对齐。登录后按文档要求在 Settings 里改掉临时密码。
如果症状不在这六个项里
排查时注意区分文档 doc/self-hosting.md Troubleshooting 一节列出的其他已知现象,它们不属于代理头问题:
- 502 / "Bad Gateway":是
puter容器没起来,而不是代理配置问题。docker compose logs puter会显示哪个依赖拒绝了它,最常见的是.env与config.json之间数据库密码不一致。 - Healthcheck 报 unhealthy 但站点能访问:容器内健康检查打的是
puter.localhost:4100/test,如果你改过domain或端口,检查仍用默认值,站点本身没有问题。 docker compose up卡在 "waiting for service to be healthy":docker compose ps看哪个容器 unhealthy;MariaDB 冷启动需要约 20–30 秒,其余服务都在 5 秒内。
以上六项检查完成后仍有问题,且日志里出现新的报错文本时,按 doc/self-hosting.md 中各条 Troubleshooting 的具体现象对号入座,不要继续修改代理规则。
【免费下载链接】puter🌐 The Internet Computer! Free, Open-Source, and Self-Hostable.项目地址: https://gitcode.com/GitHub_Trending/pu/puter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考