upstream sent too big header while reading response header from upstream
The response headers of the app are larger than the buffer nginx reads them into, because an nginx config in the chain predates the larger buffers.
Symptom
The browser shows 502 Bad Gateway while the app itself is healthy. The pages with the largest response headers fail first, typically those behind a login.
The message is in an nginx error log, and which one tells you where the fix goes.
$ grim logs nginx
$ grim logs nginx --remote=production
$ ssh root@203.0.113.10 tail /var/log/nginx/error.logThe first is the nginx inside your local stack, the second the one inside the stack on the server, the third the nginx on the server itself, in front of Traefik.
Cause
nginx reads the response headers of its upstream into one buffer, and by default that buffer is a single memory page of 4 KB. An app on grim sends more than that. The Content-Security-Policy header alone is close to 5 KB, and session cookies come on top, which is why signed-in pages fail first. A response whose headers do not fit is dropped and answered with a 502.
The configs grim writes today carry larger buffers at both places where nginx stands in the way: fastcgi_buffer_size 32k in the nginx of the stack, which talks to PHP, and proxy_buffer_size 32k in the vhost on the server, which talks to Traefik. The curse strikes where one of those files was written by a grim from before that change and never renewed.
Breaking the curse
Take the current templates first, then renew the file the log pointed at.
$ grim self-updateIn the local stack, grim upgrade rewrites docker/nginx-dev.conf, and a restart makes nginx read it.
$ grim upgrade
$ grim down
$ grim upIn the stack on the server, grim server:upgrade uploads the current docker/nginx-production.conf and recreates the containers. The next deploy would upload the same file, so a release from the updated grim breaks the curse as well.
$ grim server:upgrade shop --restartIn the vhost on the server, run grim server:add-project again with the same arguments as the first time. It keeps the .env, the database and the certificate, and writes the vhost anew.
$ grim server:add-project shop --host=vps1 --domain=shop.example.comRunning grim server:add-project again writes the vhost without the password prompt of grim server:auth. On a protected site, enable it again right after.
Verify
Ask for a page that failed, signed in, and watch the log that carried the message while you do. The 502 is gone and no new line appears.
$ curl -s -o /dev/null -w '%{http_code}\n' https://shop.example.com/admin
$ grim logs nginx --remote=production --tail=20On the server you can also look for the directive itself.
$ ssh deploy@203.0.113.10 grep fastcgi_buffer_size /opt/shop/docker/nginx-production.conf
fastcgi_buffer_size 32k;Spells that break it
grim upgrade
Renew the infrastructure files
Rewrite the Docker and nginx files of a project from the templates of the grim you have installed.
grim server:upgrade
Refresh a project's server files
Send the current docker-compose.yml and in-container nginx config to a project's server, without deploying a new image.
grim server:add-project
Give a project a home
Prepare one environment of a project on a production server, with its database, nginx vhost, certificate, compose stack and .env.
grim logs
Read the logs
Show what the containers have been printing, for one service or all of them, on your machine or on a deployed server.
grim self-update
Update grim itself
Replace the grim phar with the newest release. Projects are not touched.