直接删 access.log 会导致 Nginx 不写日志,因其仍通过文件描述符向已删除但未关闭的文件写入,且部分版本不会自动重建日志文件;正确做法是用 kill -USR1 信号通知 Nginx 重新打开日志文件。

为什么直接删 access.log 会导致 Nginx 不写日志?
因为 Nginx 启动后会持有一个指向日志文件的文件描述符(fd),即使你用 rm access.log 删除了文件,实际磁盘空间并不会立刻释放——那个 fd 还在往“已删除但未关闭”的文件里写数据。更糟的是,有些版本的 Nginx 在日志文件被删后不会自动重建,导致后续访问完全不记录。
正确做法是用 kill -USR1 发信号让 Nginx 主进程重新打开日志文件,它会按 access_log 指令中配置的路径新建一个 access.log,旧文件则可安全清理。
- 确认你的 Nginx 配置里
access_log是绝对路径,比如/www/wwwlogs/example.com.log,不是logs/access.log这种相对路径(否则切割逻辑容易错位) - 执行前先测试信号是否生效:
nginx -t && kill -USR1 $(cat /www/server/nginx/logs/nginx.pid) - 宝塔默认把 Nginx PID 写在
/www/server/nginx/logs/nginx.pid,别去读ps aux | grep nginx找进程号,容易误杀 worker 进程
怎么用 Shell 脚本实现「按天切割 + 保留 30 天」?
宝塔自带的“日志切割”功能只支持按月/周,且不支持自定义保留天数;手动写脚本反而更可控。核心逻辑三步:移动旧日志 → 发送 USR1 → 删除超期文件。
以下是一个生产环境验证过的脚本,保存为 /www/server/scripts/cut_nginx_logs.sh:
#!/bin/bash LOG_DIR="/www/wwwlogs" KEEP_DAYS=30 DATE=$(date -d "yesterday" +%Y-%m-%d)移动所有 .log 文件(排除 .log.2024-xx-xx 格式,避免重复切割)
find "$LOG_DIR" -maxdepth 1 -name ".log" ! -name ".log.*" | while read log; do [ -f "$log" ] || continue mv "$log" "${log}.${DATE}" done
通知 Nginx 重新打开日志文件
kill -USR1 $(cat /www/server/nginx/logs/nginx.pid 2>/dev/null) 2>/dev/null
删除早于 KEEP_DAYS 的切割日志(只删 .log.YYYY-MM-DD 格式)
find "$LOG_DIR" -maxdepth 1 -name ".log." -type f -mtime +$KEEP_DAYS | xargs rm -f
find ... ! -name "*.log.*"是关键:跳过已切割的文件,防止某天脚本重复运行时把access.log.2024-05-01又改成access.log.2024-05-01.2024-05-01-mtime +30表示“修改时间超过 30 天”,不是创建时间,所以必须确保切割当天就改名(脚本用yesterday是为了匹配真实访问日期)- 别用
date +%F直接取当天——Nginx 日志是滚动写的,当天的日志还在写入中,切早了会丢数据
宝塔定时任务怎么配才不踩坑?
在宝塔面板「计划任务」里添加,类型选「Shell 脚本」,脚本内容填上面的完整代码(或填路径 /www/server/scripts/cut_nginx_logs.sh),但注意三个硬性条件:
- 执行周期必须设为「每天 00:10」这类凌晨低峰时间,不能设成「每小时」或「每分钟」——
kill -USR1频繁触发可能导致 worker 进程短暂卡顿 - 脚本文件权限必须是
755,且属主是root(宝塔计划任务默认以 root 运行,但若你手贱chown www:www就会因权限不足失败) - 务必勾选「执行前先检测脚本是否存在」,否则脚本路径写错或被误删,宝塔不会报错,只会静默跳过
如果发现日志没按预期切割,去「计划任务」列表点「查看日志」,重点检查有没有 cat: /www/server/nginx/logs/nginx.pid: No such file 或 mv: cannot move 'xxx' to 'xxx.2024-05-01': Device or resource busy ——前者说明 Nginx 没跑,后者说明你脚本逻辑没避开正在写的日志文件。
哪些域名日志该切、哪些不该碰?
宝塔默认把所有站点日志都扔进 /www/wwwlogs/,但并非所有都要切割。比如:
default.log和error.log必须切——它们体积增长快,且错误日志长期不清理会影响排查效率- 用 CDN 的站点(如启用了又拍云、Cloudflare),其
access.log实际只记录回源请求,量很小,可设为保留 7 天甚至关掉访问日志 - API 接口类站点(如
api.example.com.log)建议单独配置日志路径,比如/www/wwwlogs/api/,再用独立脚本管理——避免和前端日志混在一起,删错风险高 - 千万别对
/www/wwwlogs/xxxxx.log这种带随机字符串的宝塔后台日志做切割,那是面板自身行为,格式不固定,脚本会误操作
最保险的做法:先用 ls -lt /www/wwwlogs/ | head -20 看看哪些文件最大、修改最频繁,再决定脚本里 find 的 -name 模式,而不是无差别匹配所有 *.log。