必须用 logrotate + copytruncate 替代 Caddy 自带日志轮转,因其仅重命名不清理、高并发易 EBUSY 且 FrankenPHP 不响应 USR1;copytruncate 保证原子性清空,create 确保权限正确,路径须与 Caddyfile 完全一致。

日志占满磁盘不是 FrankenPHP 写得太猛,而是它一直在往同一个文件里追加写,没人给它“换纸”——必须停用 Caddy 自带的 log roll,改用 logrotate + copytruncate 才能真正切断无限增长链。
为什么 Caddy 的 roll 参数不能用
Caddy v2.8+ 虽然支持 log 指令里的 roll 100MB,但它只是简单重命名文件,不压缩、不清理旧文件,更关键的是:rename 操作在高并发写入时可能触发 EBUSY 错误,导致日志静默丢失;且 FrankenPHP 不响应 USR1,Caddy 也无法安全刷新文件句柄。
- 现象:
access.log突然停止增长,access.log.1为空或不更新 - 风险:排查无依据,问题复现困难
- 根本缺陷:没有
copytruncate或句柄接管机制,无法保证原子性
logrotate 配置必须含 copytruncate 和 create
copytruncate 是 FrankenPHP 场景下的刚需——它先复制当前日志内容到归档文件,再清空原文件,确保 Caddy 进程持续向同一 inode 写入;create 则保证新日志文件权限正确,避免因 www-data 无法写入导致后续日志丢失。
- 路径需与
Caddyfile中log指令完全一致,例如:/var/log/frankenphp/*.log - 权限设置:
create 644 www-data www-data(CentOS/RHEL 改为apache或nginx) - 保留策略建议:
rotate 7(比默认 30 更稳妥,防小磁盘撑爆) - 触发条件推荐:
size 50M替代daily,更适合流量不均的业务
验证 logrotate 是否真正生效
配置完别只信 ls -lh 看到 .log.1 就算成功。要确认三点:原日志是否清空、新日志权限是否正确、Caddy 是否仍在写入。
立即学习“PHP免费学习笔记(深入)”;
- 手动触发并观察:
sudo logrotate -f /etc/logrotate.d/frankenphp && ls -l /var/log/frankenphp/,应看到access.log大小归零,access.log.1有内容,且属主是www-data - 实时监控写入:
sudo tail -f /var/log/frankenphp/access.log,触发一次请求,确认新日志行立即出现 - 检查 inode 使用:
df -i /var/log,若之前接近 100%,轮转后应明显回落
最容易被忽略的是日志路径一致性:Caddyfile 里写的 log /var/log/frankenphp/access.log,logrotate 配置就必须匹配这个完整路径——少一个字符,轮转就完全失效。



















