http跳https必须在caddyfile的:80 server块中用return 301实现,frankenphp自身不处理协议跳转,所有重定向必须由caddy路由层完成,且仅限:80块;php层header跳转无效,443块不接收http请求。

HTTP跳HTTPS必须在Caddyfile的:80 server块里写return
FrankenPHP自身不处理协议跳转,所有HTTP→HTTPS重定向必须由Caddy路由层完成,且只能放在监听:80的server块中。写在PHP里(比如header("Location: https://..."))或443块里都无效——前者已进PHP上下文、太晚;后者根本收不到HTTP请求。
正确做法是确保Caddyfile中有且仅有一个:80监听块,里面只放跳转逻辑:
http://yourdomain.com {
return 301 https://{host}{uri}
}
-
{host}会自动保留原始域名(含www或非www),不用硬编码 -
{uri}保留完整路径和查询参数,避免丢失?ref=abc这类内容 - 这个块里不能出现
php_server、reverse_proxy等任何处理器,否则Caddy可能忽略return - 如果域名有www和非www两种形式,两个都要显式列出,或改用通配符
*.example.com
别让CDN或Caddy自动HTTPS引发ERR_TOO_MANY_REDIRECTS
循环重定向最常见的原因是CDN(如Cloudflare)开了“Always Use HTTPS”又让Caddy自己跳一次。Caddy收到HTTP请求→301跳HTTPS→CDN再把HTTPS请求转回HTTP→Caddy又跳……浏览器直接报ERR_TOO_MANY_REDIRECTS。
排查和修复要点:
- 关掉CDN的强制HTTPS开关,让它只做TLS终止,跳转完全交给Caddy
- 检查Caddy日志:
journalctl -u caddy -f,看是否有同一请求反复匹配:80块的日志行 - 用
curl -I http://yoursite.com确认响应头只有一次Location:,状态码是301,不是302或重复跳转 - 如果你手动配置了
tls指令或用了自签名证书,Caddy的自动HTTPS会关闭,此时return 301仍是唯一可靠方式
本地开发时localhost不要跳HTTPS
在localhost或127.0.0.1上硬跳HTTPS会导致连接失败或浏览器证书警告,因为Caddy无法为本地地址申请有效Let’s Encrypt证书。
最干净的解法是在Caddyfile里加host判断:
http://localhost, http://127.0.0.1 {
respond "Development mode — no HTTPS redirect" 200
}
http://yourdomain.com {
return 301 https://{host}{uri}
}
- 顺序很重要:Caddy按块顺序匹配,把
localhost块放在前面才能拦截住 - 别用
SERVER_NAME=localhost:8080这种写法——Caddy不识别带端口的主机名,会fallback到默认行为 - 容器内跑本地服务时,
SERVER_NAME=:80才是禁用HTTPS的正解,它让Caddy跳过域名匹配和ACME流程
HTTPS监听端口不等于跳转目标端口
很多人误以为return 301 https://...里的端口要和Caddy实际监听的HTTPS端口一致。其实不然:{host}变量默认不带端口,所以https://example.com会走标准:443;但如果你的Caddy监听的是:8443,就得显式写成https://{host}:8443{uri}。
- 生产环境建议坚持用
:443,避免用户手动输端口;阿里云等平台也要求开放443才能跑Let’s Encrypt验证 - 开发时若用
:8443,记得在Docker-p映射和Caddyfile的https://跳转中保持一致 -
curl --http2 -k https://localhost:8443可验证HTTP/2是否启用,但前提是TLS已就绪——跳转配置错误会导致这步直接失败
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











