The Error
Full error from /var/log/nginx/error.log:
2024/01/15 10:23:45 [error] 12345#0: *1 upstream sent too big header while reading response header from upstream,
client: 10.0.0.1, server: example.com,
request: "GET /api/dashboard HTTP/1.1",
upstream: "http://127.0.0.1:3000/api/dashboard",
host: "example.com"
The browser gets a blank 502 Bad Gateway. Your backend is running fine β Nginx is the one choking on the response headers.
Root Cause
Nginx allocates a fixed buffer for reading response headers from upstream. Default is 4KB (or 8KB on some builds). When the upstream sends headers larger than that buffer, Nginx drops the response with this error.
4KB sounds generous until you run a real auth flow. Common culprits:
- Big session cookies β PHP sessions, Rails encrypted cookies, or JWT tokens stored in cookies can easily hit 4β8KB.
- Many
Set-Cookieheaders β OAuth flows, multi-domain auth, and feature flag systems stack cookies fast. - Verbose framework headers β Spring Boot and Django REST apps sometimes add a surprising number of custom response headers.
- CDN or auth middleware injecting headers β Cloudflare, Keycloak, or internal API gateways can balloon the header size before the response ever reaches Nginx.
The relevant Nginx directives default to values that made sense in 2005. Modern web apps routinely blow past them.
Fix
Option 1: Increase proxy buffer sizes (most common fix)
Edit your Nginx site config β usually /etc/nginx/sites-available/your-site, or the relevant server block in /etc/nginx/nginx.conf:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
# Fix: increase header buffer sizes
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
}
What each directive does:
proxy_buffer_sizeβ buffer for the first part of the upstream response (status line + headers). This is the key one for this error.proxy_buffersβ number Γ size of buffers for the full response body.proxy_busy_buffers_sizeβ max size that can be actively flushing to the client. Must not exceed the total size ofproxy_buffers.
Option 2: Apply globally in http block
Got multiple upstream services with the same problem? Set it once in the http block inside /etc/nginx/nginx.conf:
http {
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
include /etc/nginx/sites-enabled/*;
}
Per-location blocks override this global setting, so nothing with explicit values will break.
Option 3: FastCGI variant (PHP-FPM)
Running PHP via FastCGI? The directive names are different:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}
Apply the fix
# Test config syntax first
nginx -t
# Reload without downtime
systemctl reload nginx
Verify the Fix
Tail the error log while hitting the endpoint that was failing:
# Watch the error log in real time
tail -f /var/log/nginx/error.log
# Hit the endpoint that was failing
curl -v https://example.com/api/dashboard 2>&1 | grep -E '< HTTP|< Set-Cookie|< X-'
Cookie bloat is the most common trigger. Measure the actual header size with:
curl -sI https://example.com/api/dashboard | awk '{total += length($0)} END {print "Total header size: " total " bytes"}'
Anything near or over 4096 bytes confirms the root cause.
Dig Deeper: Where Are the Big Headers Coming From?
Bumping the buffers is a valid quick fix. But spend two minutes finding out what's actually bloating those headers β sometimes the right answer is trimming the cookie payload, not making Nginx's buffers bigger and bigger.
# Check response headers from your upstream directly (bypassing Nginx)
curl -sI http://127.0.0.1:3000/api/dashboard
# Get total byte count of all headers
curl -sI http://127.0.0.1:3000/api/dashboard | wc -c
When Set-Cookie is the culprit, the problem is usually in your session store. Rails' default CookieStore serializes the entire session payload into the cookie β that's the classic way a cookie hits 4KB+. Switch to Redis or a database-backed session store and the cookie shrinks to a small session ID.
Prevention
- Set the buffers proactively whenever you configure a new Nginx proxy, especially for apps that use OAuth or JWT cookies. Don't wait for users to hit 502s.
- Store sessions server-side β use Redis, Memcached, or a database instead of cookie-serialized payloads. Keep the cookie to a session ID only.
- Audit headers occasionally β auth middleware and frameworks add headers quietly over time. A quick
curl -sIonce a month catches this before it becomes an incident. - Cap cookie size in your app β a cookie crossing 4KB is almost always broken session logic, not a legitimate use case. Catch it at the application layer before Nginx does.
Tip
When debugging network-layer issues like this, I sometimes use ToolCraft's IP Subnet Calculator alongside β handy when you're also sorting out upstream internal network ranges or verifying CIDR blocks in your proxy config. Runs entirely in the browser, no data uploaded.
Quick Reference
# Minimal fix β add to your location or server block
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# Then:
nginx -t && systemctl reload nginx

