FrankenPHP容器内证书默认存于/var/lib/caddy或caddy_data目录,不持久化则重建后丢失;它完全依赖Caddy的ACME流程,不支持手动指定PEM证书。

不会自动丢失,但取决于你是否把证书持久化到外部卷或绑定挂载。 FrankenPHP 本身不生成、不存储、也不管理证书——它完全依赖 Caddy 的 ACME 自动化流程。证书由 Caddy 在首次启动时申请并存放在其内部数据目录(默认 ./caddy_data),容器重建后若该目录未持久化,证书就没了。
FrankenPHP 容器里证书存在哪儿?
Caddy 将证书(含私钥、链、ACME 账户信息)全写入 caddy_data 目录,默认路径是容器内 /var/lib/caddy 或当前工作目录下的 caddy_data。FrankenPHP 只是嵌入了 Caddy 内核,不接管这部分逻辑。
- 如果你用
docker run启动且没加-v挂载,每次docker rm+docker run都会清空这个目录 → 证书丢失,下次启动要重新申请(触发 Let's Encrypt 速率限制风险) - 如果用
docker-compose.yml,必须显式声明volumes把caddy_data映射到宿主机固定路径,例如:./caddy_data:/var/lib/caddy - FrankenPHP 的
Caddyfile里不能通过配置“指定证书文件路径”来绕过 ACME —— 它不支持手动加载 PEM 文件的 HTTPS 模式
为什么 curl -I --http3 有时显示 alt-svc 但证书又报错?
这说明 Caddy 成功启用了 HTTP/3,但证书链可能不完整或时间不同步,和证书是否“丢失”无关:
- 检查
caddy_data目录下是否有certificates/acme-v02.api.letsencrypt.org-directory/子目录和对应域名的 JSON 文件 → 存在即证书已申请成功 - 执行
docker exec -it your-frankenphp-container caddy list-commands,确认 Caddy 版本 ≥ v2.7.6(HTTP/3 + ACME 稳定支持) - 容器内系统时间不准会导致 ACME 协商失败:运行
docker exec your-frankenphp-container date,比对宿主机时间,偏差 > 2 分钟需修复(宿主机启用 NTP,容器通常继承宿主机时间) - Let's Encrypt 的 staging 环境证书不被浏览器信任,仅用于测试;生产环境必须用默认 ACME 目标(
https://acme-v02.api.letsencrypt.org/directory)
如何验证证书是否真丢了?
别只看浏览器锁图标,直接查容器内 Caddy 的状态和文件:
立即学习“PHP免费学习笔记(深入)”;
- 进入容器:
docker exec -it your-frankenphp-container sh - 查证书是否存在:
ls -l /var/lib/caddy/certificates/acme-v02.api.letsencrypt.org-directory/yourdomain.com/→ 应有certificate.pem、key.pem、issuer.crt - 查 ACME 日志:
cat /var/lib/caddy/caddy_data/logs/access.log | grep "acme",看是否有renew或obtain成功记录 - 强制触发一次检查:
caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile(若 Caddyfile 有变更)
最易被忽略的是:Caddy 的 ACME 流程需要 80 端口能被公网访问(HTTP-01 挑战),哪怕你只用 HTTPS;如果容器没暴露 80 端口、或前面有防火墙/NAT 拦截,证书根本申请不下来,重建后自然“空仓”。



















