WebSocket upgrade (Upgrade / Connection headers)
The handshake that turns one HTTP request into a two-way connection: the client sends Upgrade: websocket and Connection: Upgrade, and the server answers 101 Switching Protocols. None of it crosses a reverse proxy on its own. Both headers apply to a single hop, so nginx strips them, and proxy_pass speaks HTTP/1.0 unless told otherwise — which is why the proxy block needs proxy_http_version 1.1, proxy_set_header Upgrade $http_upgrade and proxy_set_header Connection 'upgrade'. Leave them out and the failure is silent. The page loads, nginx -t passes, /var/log/nginx/error.log stays empty, and the application's journal shows an ordinary request. Only the browser console reports the socket closing and reopening in a loop, and the access log carries a 200 where a working upgrade writes 101. Hot reload in a Next.js build breaks in exactly the same way.
Also written: Upgrade header, 101 Switching Protocols, WebSocket handshake
