Обычные HTTP-заголовки proxy не переключают соединение на WebSocket. Nginx должен явно передать Upgrade и Connection, а upstream — слушать доступный адрес.
Конфигурация
В контексте http:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
В нужном location:
location /socket/ {
proxy_pass http://app:6001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
В Docker имя app работает только в общей сети. Не публикуйте порт 6001 наружу, если Nginx уже является входной точкой.
Диагностика
Сначала nginx -t, затем reload. В DevTools ожидайте статус 101 Switching Protocols. При 502 проверьте DNS внутри контейнера Nginx, порт и журнал upstream. При мгновенном разрыве смотрите таймаут и heartbeat приложения. При 400 — путь и заголовки.
Если используется TLS, клиент подключается по wss://, а внутри сети proxy может оставаться HTTP. Не отключайте проверку origin в самом приложении: WebSocket также подвержен межсайтовым атакам.
Официальные источники