FrankenPHP不支持直接加载PEM路径,必须将fullchain.pem和privkey.pem按Caddy规范重命名为example.com.crt与example.com.key,放入/data/certificates/并设chmod 600,同时关闭自动HTTPS、确保域名完全匹配且目录权限正确。

FrankenPHP 不支持直接加载 PEM 文件路径
FrankenPHP 内部用的是 Caddy 的 TLS 管理机制,它不接受 --cert 或 --key 这类裸路径参数。你手上的 fullchain.pem 和 privkey.pem 不能像 Nginx 那样直接配置进命令行或 YAML —— Caddy 要求证书必须由它自己管理,或通过指定的目录结构“导入”。
把已有证书注入 Caddy 的 data 目录(最稳方案)
FrankenPHP 启动时会读取 Caddy 的 /data 目录(默认挂载点),其中 /data/certificates 是它查找已存在证书的地方。你需要按 Caddy 的命名规范放进去:
- 证书文件名必须是
your-domain.com.crt(注意后缀是.crt,不是.pem) - 私钥文件名必须是
your-domain.com.key - 两个文件都放在
/data/certificates/下,且权限为600(chmod 600 *.key) - 如果证书链包含中间证书,要合并进
.crt文件:先放你的域名证书,再追加中间 CA(顺序不能反)
示例操作(Docker 场景):
mkdir -p ./caddy_data/certificates cp fullchain.pem ./caddy_data/certificates/example.com.crt cp privkey.pem ./caddy_data/certificates/example.com.key chmod 600 ./caddy_data/certificates/example.com.key
然后在 compose.yaml 中确保 volume 挂载正确:
立即学习“PHP免费学习笔记(深入)”;
volumes: - ./caddy_data:/data
启动时禁用自动 HTTPS,强制走已有证书
如果不关掉自动 HTTPS,Caddy 会在首次请求时尝试申请 Let's Encrypt 证书,覆盖你手动放进去的文件。必须显式关闭:
- 设置环境变量
CADDY_AUTO_HTTPS=off - 或在
Caddyfile里写明auto_https off - 同时确保
SERVICE_NAME(或SERVER_NAME)与证书域名完全一致,包括 www 前缀
常见错误:server_name=example.com 但证书是 www.example.com → 启动不报错,但 HTTPS 握手失败,浏览器提示 NET::ERR_CERT_COMMON_NAME_INVALID。
验证证书是否生效
启动后别急着测网页,先看日志和文件状态:
- 查日志是否有
Using provided certificate或Loaded TLS certificate字样 - 进容器执行
ls -l /data/certificates/,确认文件存在且权限对 - 用
openssl s_client -connect example.com:443 -servername example.com检查实际返回的证书 subject 和 SAN 是否匹配
最容易被忽略的一点:FrankenPHP 的 Docker 镜像默认以非 root 用户运行(caddy 用户),但 /data 目录若由 root 创建,可能因权限不足无法读取 .key 文件 —— 必须提前 chown 1001:1001 ./caddy_data(1001 是 caddy 用户 UID)。



















