必须先确认日志路径和轮转策略,因PHP不直接管理日志,实际来源为Web服务器、PHP-FPM或应用层;盲目清理会导致日志丢失或空间不释放;应使用logrotate配合postrotate重载信号,并通过rsync/rclone归档,最后用lsof +L1验证句柄并重启服务释放空间。

清理前必须确认日志路径和轮转策略
PHP 本身不直接管理 logs,实际日志来源通常是 Web 服务器(如 Nginx/Apache)或 PHP-FPM,也可能是应用层用 error_log() 写入的自定义文件。盲目清理 /var/log/php* 或 /var/log/nginx/error.log 可能删掉正在被进程写入的文件——Linux 下即使文件被 rm,只要句柄未关闭,磁盘空间也不会释放,但后续新日志会写入空文件,导致丢失。
先查清楚真实日志位置和归属:
- 运行
ps aux | grep -E "(nginx|apache|php-fpm)"看主进程配置路径 - 检查
nginx.conf中error_log指令,或php-fpm.conf中的error_log和access.log - 用
lsof +D /var/log/ | grep -i "log.*w"查哪些日志文件当前正被写入
用 logrotate 替代手动 rm —— 最稳妥的备份+清理方式
手动 rm *.log 或 cat /dev/null > error.log 都有风险:前者可能中断写入,后者清空但不归档,丢了历史记录。生产环境应交由 logrotate 管理,它支持压缩、按大小/时间轮转、post-rotate 脚本归档到远端等。
示例配置(/etc/logrotate.d/php-fpm):
立即学习“PHP免费学习笔记(深入)”;
/var/log/php-fpm/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0644 www-data www-data
sharedscripts
postrotate
if [ -f /var/run/php/php-fpm.pid ]; then
kill -USR1 `cat /var/run/php/php-fpm.pid`
fi
endscript
}
关键点:
-
delaycompress:上一轮日志才压缩,方便排查时直接读明文 -
sharedscripts+postrotate:确保所有匹配日志轮转完再发信号重载,避免漏日志 -
kill -USR1是 PHP-FPM 的优雅重开日志句柄信号,Nginx 对应USR1,Apache 用graceful
备份归档不能只靠本地 rotate —— 加一层 rsync 或 rclone
logrotate 做的是本地生命周期管理,不是备份。若需保留 90 天以上或满足合规要求,得把压缩后的 .log.gz 同步走。别用 cp -r 手动拖,容易漏或覆盖。
推荐做法:
- 在
logrotate的prerotate或postrotate里调用rsync -av --remove-source-files /var/log/php-fpm/*.gz user@backup-server:/backup/php-logs/ - 或用
rclone sync /var/log/php-fpm/ remote:php-logs --include "*.gz" --max-age 7d推送到 S3/MinIO - 注意权限:备份用户需有读取
.gz文件权限,且目标目录要有写入权
清理后验证是否真正释放磁盘空间
执行完 logrotate -f /etc/logrotate.d/php-fpm 或系统定时任务后,常有人以为“删了就空了”,结果 df -h 显示空间没变——大概率是某个进程还拿着已删除日志的文件句柄。
快速定位:
- 运行
lsof +L1列出所有已删除但仍被打开的文件(标记为DEL) - 找到对应进程(如
php-fpm),重启该服务:systemctl restart php7.4-fpm(版本按实际改) - 再执行
df -h和du -sh /var/log/php-fpm/*对比,确认空间回收
这一步最容易被跳过,尤其在高负载服务上,不检查就以为清理失败,反复操作反而引发问题。











