必须挂载 /var/lib/caddy 到宿主机,否则容器重建后证书、账户密钥全丢失,触发 let’s encrypt 频率限制;挂载需完整路径、提前创建目录、确保 uid 1001 可写,还原前须停容器并校验私钥权限为 600。

自动签发的证书默认不持久——它存在容器内部的 /var/lib/caddy,容器删了,证书就没了。 你看到的“自动续期”只在容器持续运行时有效;一旦重建、重部署或磁盘清理,ACME 账户、私钥、证书链全丢,Caddy 只能重新申请,可能触发 Let’s Encrypt 频率限制。
必须挂载 /var/lib/caddy 到宿主机
FrankenPHP 不自己存证书,它完全复用 Caddy 的 ACME 存储逻辑:所有证书、账户密钥、续期状态都写死在容器内 /var/lib/caddy 下(具体路径如 /var/lib/caddy/certificates/acme-v02.api.letsencrypt.org-directory/example.com/)。不挂载,就等于没备份。
- 启动容器时加
-v $(pwd)/caddy_data:/var/lib/caddy,确保目录提前创建且可写(FrankenPHP 以 UID 1001 运行) - 别只挂载子目录(比如只挂
/var/lib/caddy/certificates),Caddy 需要整个/var/lib/caddy目录结构来管理状态文件和锁 - 如果用 Docker Compose,
volumes里明确映射:./caddy_data:/var/lib/caddy
还原前必须停容器,否则证书文件可能损坏
证书不是静态快照,Caddy 在运行中会读写 /var/lib/caddy 下的多个文件(如 acme.json、accounts 目录、证书时间戳),直接覆盖或解压正在使用的目录,会导致 ACME 流程卡死或报 acme: error loading account: invalid character。
- 还原操作前执行
docker stop frankenphp-container - 解压备份到宿主机挂载点(如
./caddy_data),不是进容器里解压 - 私钥权限必须是
600;挂载后若权限被重置,手动补一句chmod 600 ./caddy_data/certificates/example.com.key
别依赖 docker logs 或 stdout 日志来“保存”证书
有人误以为把 Caddy 启动日志输出到 stdout 就算留痕,其实证书内容根本不会打到日志里。ACME 交互过程(如 HTTP-01 挑战、证书下载)默认静默,只有失败时才报错。成功获取证书的日志只有一句 acme: Obtained certificate,不含任何密钥或 PEM 内容。
-
docker logs查不到证书文件本身,也恢复不了任何东西 - 证书是二进制敏感数据,不能靠日志轮转、Filebeat 采集等替代挂载
- 如果你用单文件打包(
frankenphp build),证书仍生成在运行时的/var/lib/caddy,同样需挂载该路径才能持久
挂载 /var/lib/caddy 是唯一可靠方式,其他都是临时缓存或日志旁路。容易被忽略的是:挂载点权限、容器 UID 匹配、还原时未停服务——这三点出问题,证书看似“存在”,实际无法加载或续期失败。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











