Nginx "upstream sent too big header while reading response header": raise the right buffer
Fix Nginx "upstream sent too big header while reading response header from upstream" and its 502: measure the headers, then raise the right buffer.
by OhSudo ··
Not sure this is your cause?Find it step by step: Website down →
Part of a learning path:Web servers: nginx and HTTPS in production
The browser shows a 502 Bad Gateway, and Nginx’s error log says why:
[error] 1234#1234: *56 upstream sent too big header while reading response header from upstream, client: 198.51.100.7, server: example.com, request: "GET /login HTTP/1.1", upstream: "http://127.0.0.1:3000/login"Your app answered. Its response headers didn’t fit in the buffer Nginx keeps for them, which is small by default: one memory page, 4 KB or 8 KB. Headers are usually tiny, so this happens when they grow, almost always because of cookies. Login flows with large tokens, such as OAuth and OpenID Connect, are the classic cause.
- Your appanswers with big headers (cookies)doesn't fit(fails)
- nginx proxy buffer4 KB or 8 KB(breaks here)so
- Browsergets 502 Bad Gateway
TL;DR
For proxy_pass, in the server or location:
proxy_buffer_size 16k;proxy_buffers 8 16k;proxy_busy_buffers_size 32k;For PHP-FPM, with fastcgi_pass:
fastcgi_buffer_size 32k;fastcgi_buffers 16 16k;Then sudo nginx -t && sudo systemctl reload nginx.
1. Find the error
sudo tail -n 20 /var/log/nginx/error.log | grep 'too big header'The upstream: part tells you which backend, and request: which page. It’s often only some pages, like the login callback, that set the big cookies.
2. Measure the headers
Ask the backend directly, bypassing Nginx, and count:
curl -s -D - -o /dev/null http://127.0.0.1:3000/login | wc -ccurl -s -D - -o /dev/null http://127.0.0.1:3000/login | grep -i '^set-cookie' | awk '{ print length }'The first number is the total size of the headers in bytes. Choose a buffer comfortably above it: 16k for headers up to about 12 KB, 32k beyond that. The HTTP Headers Analyzer shows what’s in them, if you paste the output of curl -I.
3. Raise the buffer for a proxy
location / { proxy_pass http://127.0.0.1:3000;
proxy_buffer_size 16k; proxy_buffers 8 16k; proxy_busy_buffers_size 32k;}proxy_buffer_sizeholds the headers. It’s the one that fixes this error.proxy_buffersholds the body. They’re raised alongside, as Nginx checks that the sizes fit together.proxy_busy_buffers_sizemust be at least as large as one buffer, and smaller than all of them together minus one. Otherwisenginx -trefuses the config, and says which limit is broken.
Test and reload:
sudo nginx -t && sudo systemctl reload nginx4. PHP-FPM uses its own settings
With fastcgi_pass, the proxy_* lines do nothing. Use the FastCGI ones:
location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_buffer_size 32k; fastcgi_buffers 16 16k;}The same goes for uwsgi_buffer_size with uWSGI, and grpc_buffer_size with gRPC. Laravel and WordPress sites, with many cookies from plugins, hit this often: see Nginx with Laravel and Nginx with WordPress.
5. Then shrink the headers
A bigger buffer fixes Nginx, and big headers have other costs. They travel with every response, and browsers send cookies back with every request. Browsers and other proxies have their own limits, so a CDN or load balancer in front may fail next. So also look at what’s being set:
- Session data in a cookie. Store the session on the server, and keep only an ID in the cookie.
- Several large tokens from an identity provider: keep only what the app needs.
- Duplicated
Set-Cookieheaders, from a bug that sets the same cookie many times.
6. The other direction: big request headers
If the browser sends too much, the error is different, and comes earlier:
400 Bad RequestRequest Header Or Cookie Too LargeThat’s governed by large_client_header_buffers, for example large_client_header_buffers 4 16k;. Clearing cookies for the site fixes it for one user, and shrinking them fixes it for all.
Warning
Don’t set the buffers to megabytes “to be safe”. They’re allocated per connection, so on a busy server, large values add up to a lot of memory. Measure, and choose the smallest size that fits with some room. And turning proxy_buffering off doesn’t help here, as headers are still read into proxy_buffer_size.
Shell, we have a problem!
Similar, but different: a 502 Bad Gateway with connect() failed (111: Connection refused) means the backend isn’t listening. 504 Gateway Time-out means it’s too slow. 413 Request Entity Too Large is about request bodies. The Nginx Config Generator writes a complete reverse proxy config. could not build server_names_hash is another size to raise, for long server names.
Found this useful? Share it.
Found a mistake? Let us know at contact@ohsudo.com.