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

FrankenPHP 不能直接用 fullchain.pem 和 privkey.pem 路径配置 HTTPS —— 它底层复用 Caddy 的证书加载逻辑,只认特定命名、特定位置、特定权限的文件。
证书必须重命名为 example.com.crt 和 example.com.key
Caddy(也就是 FrankenPHP)不解析任意 PEM 路径,只从 /data/certificates/ 目录下按域名+固定后缀匹配文件。你手上的证书必须严格满足:
- 域名证书(含完整链)保存为
example.com.crt,不能是fullchain.pem或cert.pem - 私钥保存为
example.com.key,不能是privkey.pem - 若证书含中间 CA,需手动合并:先写入你的域名证书,再追加中间证书(顺序错会导致浏览器报
ERR_CERT_AUTHORITY_INVALID)
文件必须放进 /data/certificates/ 并设 chmod 600
FrankenPHP 启动时默认挂载宿主机的 ./caddy_data:/data,它只读取 /data/certificates/ 下的证书。操作要点:
- 创建目录:
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(私钥绝不能组/其他可读) - 确认属主:运行用户(如
www-data)必须能读取该文件,否则启动时报open /data/certificates/example.com.key: permission denied
必须关闭自动 HTTPS 并确保域名完全匹配
如果不关自动 HTTPS,Caddy 会在首次请求时覆盖你放好的证书,去申请 Let's Encrypt 的新证书。关键设置:
- 环境变量设为
CADDY_AUTO_HTTPS=off(Docker Compose 中加在environment:下) - 或在
Caddyfile全局块写auto_https off -
SERVICE_NAME(或SERVER_NAME)值必须和证书 CN/Subject Alternative Name 完全一致,包括www.前缀 ——server_name=example.com但证书是www.example.com,握手会失败,日志里看不到错误,浏览器只显示NET::ERR_CERT_COMMON_NAME_INVALID
验证证书是否被正确加载
别只测网页能不能打开,要查两个地方:
- 启动日志里找
Using provided certificate或Loaded TLS certificate字样,没出现说明没读到 - 进容器执行:
ls -l /data/certificates/,确认文件存在、权限是-rw-------、属主匹配运行用户 - 用
curl -Iv https://example.com看响应头是否有SSL certificate verify ok,且证书信息与你放的一致
最容易被忽略的是域名匹配粒度和父目录权限 —— 即使 .key 文件权限正确,如果 /data/certificates/ 目录本身是 755 且对其他用户可遍历,就可能被覆盖或替换;而域名少个 www 或大小写不一致,证书就等于没生效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











