nginx日志需借助logrotate或脚本实现按天/小时切割:推荐logrotate配置daily+postrotate发送usr1信号;按小时可配hourly或cron调用;自定义脚本需手动mv日志并kill -usr1。

Nginx 本身不支持原生的日志自动按天或按小时切割,需要借助外部工具(如 logrotate)或脚本配合实现。最常用、稳定且生产环境推荐的方式是使用系统自带的 logrotate 工具来完成。
用 logrotate 实现按天切割 access_log
logrotate 是 Linux 系统中专门管理日志轮转的工具,配置简单、可靠性高,支持压缩、保留天数、触发后执行命令等特性。
- 创建配置文件,例如:
/etc/logrotate.d/nginx - 写入以下内容(假设你的 access_log 路径是
/var/log/nginx/access.log):
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0644 www-data www-data
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
说明:
-
daily:每天切割一次 -
rotate 30:最多保留 30 个归档日志(即 30 天) -
compress:切割后用 gzip 压缩旧日志 -
postrotate ... endscript:切割完成后向 Nginx 主进程发送USR1信号,让其重新打开新的 access_log 文件(这是关键!否则 Nginx 还会往旧文件写)
按小时切割 access_log
logrotate 默认不支持“每小时”,但可以通过 cron 配合手动触发实现。
- 修改 logrotate 配置,去掉
daily,加上hourly(需确保 logrotate 版本 ≥ 3.8.0) - 或者更通用的做法:在 crontab 中每小时调用一次 logrotate:
注意:
- 确保配置里把
daily换成hourly,并把rotate数值调大(如rotate 72表示保留最近 3 天的每小时日志) - 同样必须保留
postrotate发送 USR1 信号,否则日志不会切到新文件
不依赖 logrotate 的轻量方案(Shell 脚本 + cron)
适合资源受限或定制化需求强的场景,比如要给日志加时间戳命名、同步到远程等。
- 写一个切割脚本
/usr/local/bin/nginx-log-rotate.sh:
LOG_DIR="/var/log/nginx"
ACCESS_LOG="$LOG_DIR/access.log"
DATE=$(date -d "yesterday" +%Y%m%d_%H)
mv "$ACCESS_LOG" "$LOG_DIR/access_${DATE}.log"
kill -USR1 $(cat /var/run/nginx.pid)
- 加可执行权限:
chmod +x /usr/local/bin/nginx-log-rotate.sh - 加入 crontab(例如每小时整点执行):
0 * * * * /usr/local/bin/nginx-log-rotate.sh
优点是灵活;缺点是需自行处理压缩、清理、错误判断等逻辑。
验证和常见问题
切割是否生效?关键看两点:
- 旧日志文件是否已重命名/移动(如出现
access_20240501_14.log) - 原
access.log是否变为空文件且有最新写入(用tail -f观察) - 如果日志还在往旧文件写,大概率是没成功发送
USR1信号,检查 pid 文件路径和权限 - Nginx 必须以 master process 方式运行(默认如此),否则
kill -USR1不起作用
不复杂但容易忽略。











