[crit] 17067#0: *4093530 open() "/home/nginx//client_body_temp/0000048707"
failed (13: Permission denied), client: 127.0.0.1,server: localhost, request: "POST /url/create HTTP/1.1", host: "127.0.0.1"



[error] 17067#0: *4093530 open() "/home/nginx//html/50x.html" failed (13: P
ermission denied), client: 127.0.0.1, server: localhost, request: "POST /url/create HTTP/1.1", host: "127.0.0.1"

1. 问题原因分析

这个问题基本可以锁定是 Nginx 临时文件目录的权限问题,属于一个非常经典且容易复现的故障。Nginx 服务器上同一接口有时返回 500(Internal Server Error)或 403(Forbidden)错误,并提到 client_body_temp,这通常与 Nginx 处理客户端请求体(如 POST 数据)时的临时文件存储相关。这类问题往往是间歇性的,可能由权限、资源限制或配置错误引起。

500错误通常表示服务器内部错误,可能是后端应用(如PHP、Python脚本)出了问题。
403错误通常表示禁止访问,可能是权限问题或配置问题。
“client_body_temp”是Nginx用来存储客户端请求体(如POST请求中的表单数据)的临时目录。如果这个目录不存在或权限不正确,可能会导致问题。
间歇性出现:问题“有时”发生,可能是因为:
高并发请求导致临时目录资源竞争。
磁盘空间或 inode 不足时好时坏。
配置中的缓冲区大小不足,使得大请求体偶尔溢出。

2. 诊断和检查步骤

步骤 1: 检查 client_body_temp 目录状态

 - **确认目录路径**:Nginx 默认临时目录通常是 `/var/lib/nginx/body` 或 `/tmp/nginx-body`,具体取决于安装方式。运行命令查看配置:
   ```bash
   grep client_body_temp_path /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf
   ```
   如果没有明确设置,Nginx 会使用编译时的默认路径(通常是 `/var/lib/nginx/body`)。
 - **检查目录是否存在和权限**:
   ```bash
   # 假设目录是 /var/lib/nginx/body(根据上一步调整)
   ls -ld /var/lib/nginx/body
   ```
   - 输出应显示目录所有者是 Nginx 进程用户(通常是 `nginx` 或 `www-data`)。例如:
     ```
     drwx------ 2 nginx nginx 4096 Jun 10 10:00 /var/lib/nginx/body
     ```
   - 如果目录不存在,创建它:
     ```bash
     sudo mkdir -p /var/lib/nginx/body
     ```
 - **验证权限**:Nginx 用户必须拥有读写权限。运行:
   ```bash
   sudo chown nginx:nginx /var/lib/nginx/body  # 根据实际用户调整,如 www-data
   sudo chmod 700 /var/lib/nginx/body  #

步骤 2: 检查磁盘资源和 inode

 - **磁盘空间不足**:临时目录所在分区空间满会导致写入失败。运行:
   ```bash
   df -h /var/lib/nginx  # 检查分区使用情况
   ```
   如果使用率接近 $100\%$,需要清理旧文件或扩展磁盘。
 - **inode 耗尽**:临时文件过多可能耗尽 inode(文件系统索引)。运行:
   ```bash
   df -i /var/lib/nginx  # 查看 inode 使用率
   ```
   如果接近 $100\%$,删除不必要的临时文件:
   ```bash
   sudo find /var/lib/nginx/body -type f -mtime +1 -delete  # 删除超过1天的旧文件
   ```

步骤 3: 检查 Nginx 配置和日志

 - **查看错误日志**:Nginx 错误日志通常记录 500/403 的详细信息。运行:
   ```bash
   sudo tail -f /var/log/nginx/error.log  # 实时监控日志,复现问题时观察
   ```
   查找与 `client_body_temp` 相关的错误,例如:
   ```
   open() "/var/lib/nginx/body/0000000001" failed (13: Permission denied)
   ```
   或
   ```
   client intended to send too large body
   ```
 - **验证配置参数**:
   - 确保 `client_body_buffer_size` 足够大(默认 8k 或 16k)。大请求体(如文件上传)需要更大缓冲区,否则会频繁写入临时文件。例如:
     ```nginx
     http {
         client_body_buffer_size 16k;  # 可以增加到 64k 或 128k 测试
         client_body_temp_path /var/lib/nginx/body;  # 确保路径正确
         client_max_body_size 10m;  # 限制请求体大小,避免过大请求
     }
     ```
   - 在 `server` 或 `location` 块中添加这些设置,针对特定接口优化。
 - **测试配置**:修改后,检查语法并重载:
   ```bash
   sudo nginx -t  # 测试配置语法
   sudo systemctl reload nginx  # 重载服务,不中断运行
   ```

步骤 4: 复现问题并监控

 - 使用工具如 `curl` 或 `ab` (Apache Bench) 模拟请求:
   ```bash
   curl -X POST http://your-interface-url -d "large_data=..."  # 发送大请求体测试
   ```
 - 监控系统资源:
   ```bash
   top  # 查看 CPU/内存
   iotop  # 查看磁盘 I/O,检查临时文件写入是否正常
   ```

3. 解决方案

原因1:请求体太大,默认只有1m,可设置max body

nginx中的client_max_body_size配置项用来限制客户端发送给服务器的请求正文的最大字节数。这个配置项可以在http, server, location级别配置,如果在location中配置,那么会覆盖server级别的配置。默认值是1m。

设置方法如下:

http {
    client_max_body_size 10m;
    ...
}
或者

server {
    client_max_body_size 20m;
    ...
}
或者

location /upload {
    client_max_body_size 50m;
    ...
}
如果客户端发送的请求正文大小超过了设置的限制,nginx会返回413、500、403等错误码。

原因2:服务目录无权限访问

nginx服务由更高权限的账号启动,如root启动,但是worker为nginx等普通账号

chown nginx:nginx * -R

# 用root把nginx 停掉
nginx -s stop

# 用普通账号,如nginx 把服务重新启动

sudo -u nginx -iH
nginx -s /home/nginx/conf/nginx.conf

Nginx 在处理 POST 请求时,会根据请求体的大小决定数据的存放位置:

  1. 小请求体:如果请求体小于 client_body_buffer_size,数据会直接存内存里,不读写磁盘。此时即使 client_body_temp 目录权限有问题,请求也能通过。

  2. 大请求体:如果请求体大于 client_body_buffer_size,Nginx 会把数据写入 client_body_temp 这个临时目录。此时如果 Nginx 工作进程没有该目录的写入权限,就会报错。

4. 预防措施

  • 监控和告警:使用工具(如 Prometheus + Grafana)监控磁盘空间、inode 和 Nginx 错误日志。
  • 优化配置:针对高流量接口,在 location 块中单独设置缓冲区大小。
  • 定期维护:添加日志轮转和临时文件清理脚本。
  • 测试环境验证:在非生产环境模拟高负载测试。

如果以上步骤后问题仍存在,请提供更多细节(如 Nginx 版本、错误日志片段、服务器操作系统),我会进一步帮助您分析。记住,修改配置后重载 Nginx(sudo systemctl reload nginx),无需重启服务。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐