FrankenPHP的HTTPS证书由Caddy自动管理,不可直接复制到另一台Caddy使用;硬拷贝会导致ACME账户不匹配、续期失败或证书被拒,应让目标Caddy独立申请证书或通过共享存储+显式tls指令安全复用。

不能直接复用。FrankenPHP 的 HTTPS 证书由 Caddy 自动管理,但证书文件路径、存储结构和所有权绑定的是运行 FrankenPHP 的那个 Caddy 实例及其数据目录,硬拷贝到另一台 Caddy 上大概率会失败——不是权限问题,就是 ACME 账户或密钥不匹配。
证书文件本身能复制,但 Caddy 不会认
Caddy 把证书存在 /data/certificates/(默认)下,按域名组织,含 certificate.crt、private_key.key 和 issuer_certificate.crt。你当然可以 scp 过去,但另一台 Caddy 启动时不会加载这些文件,除非你显式配置 tls /path/to/cert.crt /path/to/key.key —— 这会绕过 ACME 流程,变成手动 TLS 模式。
- 手动指定证书后,Caddy 不再自动续期,到期就得自己换
- 如果原 FrankenPHP 实例用的是 Let’s Encrypt staging 环境,证书在生产 Caddy 上会被拒绝(浏览器报
NET::ERR_CERT_AUTHORITY_INVALID) - 私钥文件权限必须是
600,且属主得是运行 Caddy 的用户,否则启动报open /path/to/key.key: permission denied
更稳妥的做法:让目标 Caddy 自己申请
只要域名 DNS 解析正确、80/443 端口可访问,新 Caddy 就能独立完成 ACME 流程。FrankenPHP 的证书对它毫无价值,反而是干扰源。
- 确保新机器的
CADDY_CONFIG或 Caddyfile 中没写死旧证书路径 - 删掉
/data目录下所有已存在的证书缓存(rm -rf /data/certificates/*),避免 Caddy 试图复用失效状态 - 首次启动时加
-adapter caddyfile并观察日志里是否出现obtaining certificate,而不是loading existing certificate
如果必须共享证书(比如内网多实例负载均衡)
那就别碰 Caddy 的自动管理,改用外部证书注入方式:
立即学习“PHP免费学习笔记(深入)”;
- 把证书 + 私钥放在共享存储(如 NFS)或配置中心(Consul/Vault)
- 在每台 Caddy 的 Caddyfile 中用
tls /shared/cert.crt /shared/key.key显式引用 - 配合外部工具(如
certbot或acme.sh)统一续期,并触发 Caddy reload - 注意:FrankenPHP 的
php_server指令不参与 TLS 终止,它只管 PHP 请求转发,HTTPS 层完全由 Caddy 处理
真正容易被忽略的是 ACME 账户绑定——Caddy 把账户密钥存在 /data/acme 下,它和证书是成对的。只搬证书不搬账户密钥,新实例续期时会新建账户,导致 Let’s Encrypt 认为是新站点,可能触发速率限制。



















