Nginx访问日志切割脚本,按天分割日志文件
Nginx访问日志默认写入同一个文件,时间一长文件会变得很大,不仅占用磁盘空间,打开和检索也会变慢。
本文介绍如何用系统自带的logrotate工具,配合一个简单的切割脚本,实现Nginx访问日志按天自动分割,适合刚接触服务器运维的读者。
检查环境与准备切割目录
开始之前,先确认Nginx日志的实际路径。
执行以下命令查看Nginx配置中access_log的指向:
grep -r "access_log" /etc/nginx/nginx.conf /etc/nginx/conf.d/ 2>/dev/null
常见的日志路径是/var/log/nginx/access.log。
如果使用了宝塔面板,路径通常是/www/wwwlogs/你的域名.log。
确认路径后,创建用于存放历史日志的目录,例如:
mkdir -p /var/log/nginx/oldlogs
注意:目录权限要和Nginx运行用户一致,通常为www-data或nginx,否则切割后可能无法写入。
可以用ps aux | grep nginx查看运行用户。
编写日志切割脚本
虽然logrotate可以自动切割,但配合一个自定义脚本能更灵活地控制重命名和清理。
新建脚本文件:
vim /usr/local/bin/nginx_log_cut.sh
写入以下内容:
#!/bin/bash
LOG_DIR="/var/log/nginx"
OLD_DIR="/var/log/nginx/oldlogs"
DATE=$(date -d "yesterday" +%Y%m%d)
mv ${LOG_DIR}/access.log ${OLD_DIR}/access_${DATE}.log
# 通知Nginx重新打开日志文件
kill -USR1 $(cat /run/nginx.pid)
# 删除30天前的日志
find ${OLD_DIR} -name "access_*.log" -mtime +30 -delete
保存后赋予执行权限:
chmod +x /usr/local/bin/nginx_log_cut.sh
脚本逻辑是:
把当前access.log重命名为带日期的文件,
然后发送USR1信号让Nginx重新打开新日志文件,
最后删除30天前的旧日志。kill -USR1是Nginx切割日志的标准做法,
不会中断服务。
配置logrotate按天自动执行
系统一般已安装logrotate,直接创建配置文件:
vim /etc/logrotate.d/nginx
写入以下内容:
/var/log/nginx/access.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 $(cat /run/nginx.pid)
endscript
}
关键参数说明:daily表示每天切割一次;rotate 30保留30份历史日志;compress启用gzip压缩节省空间;create指定新日志文件的权限和属主。如果使用自定义脚本,
可以去掉postrotate部分,
改为在crontab中调用脚本。
如果选择用crontab执行脚本,添加定时任务:
crontab -e
加入一行,表示每天凌晨0点1分执行:
1 0 * * * /usr/local/bin/nginx_log_cut.sh
验证切割是否生效
配置完成后,可以手动触发一次logrotate测试:
logrotate -vf /etc/logrotate.d/nginx
-v显示详细过程,-f强制立即切割。
执行后查看日志目录:
ls -lh /var/log/nginx/
应该能看到access.log重新生成,同时出现类似access.log-20250101或access_20250101.log的历史文件。
检查Nginx进程是否正常:
systemctl status nginx
如果服务运行正常,且新日志文件开始写入内容,说明切割成功。
常见报错与避坑指南
报错1:kill: (1234) - No such process
原因:Nginx的pid文件路径不对。用find / -name nginx.pid 2>/dev/null找到实际路径,修改脚本中的/run/nginx.pid。
报错2:切割后日志文件为空
检查Nginx是否真的重新打开了日志。手动执行kill -USR1 $(cat /run/nginx.pid),然后访问网站,看新日志是否有内容。如果没有,可能是SELinux或AppArmor限制了写入,临时关闭测试:setenforce 0。
避坑1:不要直接删除access.log
直接rm会导致Nginx继续向已删除的文件句柄写入,磁盘空间不会释放。必须先重命名,再发信号。
避坑2:logrotate和自定义脚本不要重复执行
如果同时配置了logrotate的postrotate和crontab脚本,可能导致同一天切割两次。建议二选一:要么用logrotate全自动,要么用crontab调用脚本。
避坑3:权限问题
oldlogs目录的属主必须是Nginx运行用户,否则mv操作可能失败。可以用chown www-data:adm /var/log/nginx/oldlogs修正。
几个常见疑问
日志切割后需要重启Nginx吗?
不需要。发送USR1信号是平滑重开日志,不会中断现有连接。只有修改了Nginx主配置文件才需要reload。
可以按小时切割吗?
可以。在logrotate配置中将daily改为hourly,并确保logrotate的cron任务支持每小时执行。或者修改脚本中的date格式为+%Y%m%d%H。
宝塔面板的Nginx日志怎么切割?
宝塔默认已启用日志切割,路径在/www/wwwlogs/下。如果未生效,检查/etc/logrotate.d/下是否有对应规则,或直接在面板的“计划任务”中添加shell脚本。
历史日志太多怎么办?
调整rotate数值,比如改为rotate 7只保留7天。或者结合find命令定期清理,如find /var/log/nginx/oldlogs -mtime +7 -delete。
按照以上步骤操作后,Nginx访问日志就会每天自动分割、压缩并清理,磁盘空间和排查效率都能得到改善。
建议先在测试环境验证脚本,再部署到生产服务器。