Warning in the nginx log, need explanation of the request
The most common mistake with this warning is treating it as an error and raising every buffer in nginx.conf until it disappears. It isn't an error. The request worked, and nginx is just telling you it used the disk. If you searched "warning in the nginx log, need explanation of the request", this walks through reading the line, finding what caused it, and fixing it only where it matters.
A [warn] line saying a request body or upstream response "is buffered to a temporary file" means the data was bigger than nginx's memory buffers, so nginx wrote it to disk. The request still succeeded. The request: field shows which URL caused it. Raise client_body_buffer_size or fastcgi_buffers for that location only if it happens often.
What the nginx "buffered to a temporary file" warning means
Running example: a Laravel admin panel on a VPS, nginx in front of PHP-FPM. The error log shows two kinds of lines:
2026/10/20 09:14:02 [warn] 2154#2154: *8812 a client request body is buffered to a temporary file /var/lib/nginx/body/0000000007, client: 203.0.113.50, server: example.com, request: "POST /admin/uploads HTTP/1.1", host: "example.com"
2026/10/20 09:15:40 [warn] 2154#2154: *8840 an upstream response is buffered to a temporary file /var/lib/nginx/fastcgi/2/00/0000000002 while reading upstream, client: 203.0.113.50, server: example.com, request: "GET /reports/download HTTP/1.1", upstream: "fastcgi://unix:/run/php/php-fpm.sock:", host: "example.com"
The first is about data coming in (an upload). The second is about data going out (PHP's response). Both say the same thing: it didn't fit in memory, so nginx spooled it to a file and carried on.
Warning in the nginx log, need explanation of the request? Fix it in 6 steps
Step 1: Pull the warnings and split the fields
sudo grep '\[warn\]' /var/log/nginx/error.log | tail -n 20
Every line follows the same layout:
2026/10/20 09:14:02is the time,[warn]is the level.2154#2154is the worker PID and thread ID. You can ignore it.*8812is the connection ID. Use it to find other lines from the same connection.client:is the IP that sent the request. If it's always your load balancer or Cloudflare, the X-Real-IP fix for nginx gets you the real visitor address.request:is the method, URL and protocol. This is the part you actually care about.upstream:is the backend nginx was talking to. If that term's new, here's what upstream means in nginx.
Step 2: Count which URLs trigger it
One warning a week is noise. Hundreds on one URL is worth a look:
sudo grep 'buffered to a temporary file' /var/log/nginx/error.log \
| grep -o 'request: "[^"]*"' | sort | uniq -c | sort -rn | head
In the running example you'd see POST /admin/uploads and GET /reports/download at the top. Both make sense: uploads are big requests, downloads are big responses.
Step 3: Check your current buffer sizes
Dump the full loaded config and look for the relevant directives:
sudo nginx -T 2>/dev/null | grep -E 'client_body_buffer_size|fastcgi_buffers|fastcgi_buffer_size|fastcgi_max_temp_file_size'
If nothing prints, you're on nginx's defaults, which are small: a couple of memory pages for the request body and a handful of small buffers for the FastCGI response. Measure what you're actually sending:
curl -s -o /dev/null -w '%{size_download}\n' -H 'Cookie: laravel_session=YOUR_SESSION' https://example.com/reports/download
If that prints several megabytes, no reasonable memory buffer will hold it, and that's fine.
Step 4: Fix the request body warning for uploads only
For the upload route, raise the body buffer in that location only:
location = /admin/uploads {
client_max_body_size 20m;
client_body_buffer_size 1m;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root/index.php;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
Don't copy client_body_buffer_size up to the same value as client_max_body_size, and don't set it in the http block. It's memory reserved per request, so a large global value means every concurrent upload can grab that much RAM. Files bigger than the buffer will still go to disk, and that's the correct behaviour.
Step 5: Fix the upstream response warning for downloads
For normal pages, slightly bigger FastCGI buffers usually stop the warning:
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_buffer_size 16k;
fastcgi_buffers 16 16k;
}
For real file downloads, I'd stop sending the file through PHP at all. Let nginx serve it with X-Accel-Redirect:
location /protected-exports/ {
internal;
alias /var/www/app/storage/app/exports/;
}
return response('', 200, [
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="report.csv"',
'X-Accel-Redirect' => '/protected-exports/report.csv',
]);
Laravel still checks auth, but nginx streams the file from disk, and the PHP worker is free immediately. The internal line stops anyone requesting /protected-exports/ directly.
What I'd skip: fastcgi_max_temp_file_size 0;. It removes the warning, but then a slow client holds the PHP-FPM worker until the whole response is sent, which is worse than a temp file. Same for setting error_log ... error; to hide warnings. You'll hide the next warning that does matter.
Step 6: Check the temp directory if uploads fail
There's a nastier cousin of this warning. If nginx can't write the temp file, it logs a [crit] line and the request fails with a 500:
[crit] 2154#2154: *8901 open() "/var/lib/nginx/body/0000000011" failed (13: Permission denied), client: 203.0.113.50, server: example.com, request: "POST /admin/uploads HTTP/1.1", host: "example.com"
This usually happens after changing the user directive in nginx.conf. Fix the ownership to match your nginx user (www-data on Debian and Ubuntu):
sudo chown -R www-data:www-data /var/lib/nginx
Paths differ by distro. RHEL-based systems keep these under /var/lib/nginx/tmp/. The open() path in the log tells you exactly where to look.
Verify the warning is gone for that request
Reload and repeat the same request:
sudo nginx -t && sudo systemctl reload nginx
sudo tail -f /var/log/nginx/error.log | grep --line-buffered 'buffered to a temporary file'
Upload a file of the size your users normally send, then download the report. Small and medium requests should no longer produce a line. Very large uploads will still log the warning, and that's expected. If you want to see how long those requests take, the timing log format in the nginx 499 guide adds $request_time to your access log.
Next steps
Leave nginx's other defaults alone unless a log line points at them. If you're seeing [crit] or [error] lines alongside these warnings and can't place them, contact HeadsNTail with a few sample lines.
FAQ
Is "a client request body is buffered to a temporary file" an error?
No. It's a [warn] level message and the request completes normally. It only means the upload was bigger than client_body_buffer_size, so nginx stored it on disk first.
Where does nginx store temporary files?
In the paths set by client_body_temp_path, fastcgi_temp_path and proxy_temp_path. On Debian and Ubuntu these default to subfolders of /var/lib/nginx/. The exact path appears in the warning itself.
What's the difference between this warning and "upstream sent too big header"?
"Buffered to a temporary file" is about the response body and is harmless. "Upstream sent too big header while reading response header from upstream" is an [error] that returns a 502, usually from large cookies or headers. Raise fastcgi_buffer_size (or proxy_buffer_size) to fix that one.
Does the same warning appear with proxy_pass?
Yes, with a /var/lib/nginx/proxy/ path instead. The fixes are the proxy versions of the same directives: proxy_buffer_size, proxy_buffers and X-Accel-Redirect for downloads.
Next time you see a warning in the nginx log, need explanation of the request, start with the request: field and Step 2's count before touching any buffer.


