磁盘空间满导致Nginx日志写入失败,表现为access_log和error_log停更且无错误提示;需检查日志路径存在性、权限、Inode耗尽、deleted文件占用及SELinux/AppArmor限制,并通过strace、df、lsof等定位根因。

磁盘空间满导致 Nginx 日志写入失败,最典型的表现是 access_log 和 error_log 停更、但 error_log 里又查不到相关错误——因为写入失败发生在 worker 进程运行时,Nginx 默认静默丢弃日志,不报错、不重试、也不中断请求。
确认日志是否真在写、写到哪了
别默认看 /var/log/nginx/error.log。先打开 nginx.conf,检查 error_log 和 access_log 指令的实际路径。常见问题:配置写了 /data/logs/nginx/access.log,但目录 /data/logs/nginx/ 根本不存在,或权限不对,导致 Nginx 启动时连日志模块都没初始化成功。
- 运行
ps aux | grep nginx,确认 worker 进程使用的是哪个用户(如nginx或www-data) - 用
ls -ld /data/logs/nginx/检查该用户对日志路径的父目录是否有 w(写)和 x(进入)权限;若路径含多级(如/a/b/c),每一级都必须存在且可进入 - 执行
nginx -c /etc/nginx/nginx.conf -e stderr,强制把启动错误输出到终端,能捕获“路径不可写”“模块加载失败”等早期问题
快速验证磁盘与 Inode 是否真的耗尽
磁盘块(block)或 Inode 耗尽都会让日志写不进去,但表现不同:
-
df -h:看日志所在分区的Use%是否为 100%,Avail是否为 0 -
df -i:重点看IUse%,达 100% 表示无法创建新文件——这常出现在 logrotate 生成大量.log.1、.log.2.gz后未清理 -
lsof +L1 | grep nginx:查是否有已删除但仍被 worker 占用的“deleted”日志文件,这是删了日志却没释放空间的明确信号
绕过日志本身,直接看系统层反馈
当 error_log 已停更,就得跳过日志,从系统调用层面抓失败原因:
- 用
strace -p $(pgrep -f "nginx: worker") -e trace=write,openat,fsync -s 256 2>&1 | grep -E "(log|denied|No space)",观察 write 系统调用是否返回-1 ENOSPC(空间满)或-1 EACCES(权限拒绝) - 查 SELinux 干预:
ausearch -m avc -ts recent | grep nginx(CentOS/RHEL);查 AppArmor:aa-status | grep nginx(Ubuntu) - 检查是否因 logrotate 后未发 USR1 信号:worker 仍在往已删除文件的旧句柄写入,系统返回
EBADF,Nginx 静默跳过
临时恢复 + 长效加固
定位问题后,需立即释放空间并防止复现:
- 安全清空:用
echo "" > /path/to/access.log覆盖内容,比rm更稳妥;若已删文件但句柄未释放,执行nginx -s reopen或kill -USR1 $(cat /var/run/nginx.pid) - logrotate 必须配
create 0644 nginx nginx和postrotate ... kill -USR1 ... endscript,确保轮转后立即切换新文件 - 限制单个日志大小:
size=100M比单纯daily更可靠;高流量站点建议关闭非必要 access_log,或设为access_log /dev/null - 给 error_log 加缓冲:
error_log /var/log/nginx/error.log warn buffer=64k flush=5s;,降低写入失败概率


















