nginx不支持原生日志按日期分割,推荐使用logrotate配合固定日志路径实现每日轮转;也可用cron触发usr1信号重开日志,但需确保pid文件可访问且权限正确。

Nginx 本身不支持原生的按日期自动分割 access_log 文件,但可以通过配置日志路径结合外部工具(如 logrotate)或利用 Nginx 的变量动态生成文件名来间接实现。最常用且可靠的方式是配合系统日志轮转工具,辅以 Nginx 日志格式与命名约定。
使用 $time_iso8601 变量动态生成日志文件名
虽然不能真正“实时按天切分”,但可在 log_format 中嵌入时间变量,并在 access_log 指令中引用,使每次 reload 或 reopen 时生成带日期的文件名。需配合定时重载或信号触发:
- 定义含日期的日志格式,例如:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'; - 在 server 或 http 块中使用变量构造文件名:
access_log /var/log/nginx/access_$(date +\%Y\%m\%d).log main; ❌ 这样写 Nginx 启动会报错——Nginx 不解析 shell 命令。 - 正确做法是借助 $time_iso8601 中的年月日部分(需注意该变量每秒刷新,不能直接用于文件名);更稳妥的是用 logrotate 配合固定文件名 + daily 切割。
推荐方案:logrotate 按天轮转 access.log
这是生产环境最稳定、兼容性最好的方式。Nginx 写入固定路径(如 /var/log/nginx/access.log),由 logrotate 每日归档并通知 Nginx 重新打开日志文件:
- 编辑 /etc/logrotate.d/nginx,内容示例:
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0644 www-data www-data
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
invoke-rc.d nginx rotate >/dev/null 2>&1
fi
endscript
} - 关键点:sharedscripts 确保所有匹配日志只执行一次 postrotate;postrotate 中调用 nginx -s reopen 或 systemctl reload nginx,让 worker 进程打开新日志文件。
- 验证:手动运行 logrotate -f /etc/logrotate.d/nginx,检查是否生成 access.log.1 并观察 Nginx 是否继续写入 access.log。
进阶:用 cron + date + kill -USR1 实现轻量级切割
若无法使用 logrotate(如容器环境),可用定时任务每日触发日志 reopen:
- 添加 crontab 条目(每天 00:00 执行):
0 0 * * * /bin/kill -USR1 $(cat /var/run/nginx.pid 2>/dev/null) 2>/dev/null || true - 前提:Nginx 启动时指定 pid 文件路径(pid /var/run/nginx.pid;),且该路径可被 cron 访问。
- USR1 信号会通知 master 进程重新打开日志文件,worker 进程随即切换到新文件(原文件保留,可配合 mv + gzip 自定义归档逻辑)。
注意事项与常见问题
避免踩坑的关键细节:
- 确保日志目录有写权限(尤其 www-data 或 nginx 用户);
- 不要在 access_log 路径中直接写 $year$month$day —— Nginx 不支持变量用于文件名,仅支持内置变量如 $bytes_sent 在 log_format 中;
- logrotate 的 create 参数必须匹配 Nginx 工作用户(如 www-data),否则新日志无法写入;
- 容器中建议挂载宿主机日志目录 + 外部 logrotate,或使用 sidecar 容器轮转,而非依赖容器内 cron。











