Blog / Java/Kotlin / Nginx 프록시 환경에서의 WebSocket (WSS) 동작 이상 트러블슈팅

Nginx 프록시 환경에서의 WebSocket (WSS) 동작 이상 트러블슈팅

블로그 게시글이 발행되면 Kafka로 메시지를 발행하고, Web 모듈에서 메시지를 수신하여 웹소켓을 통해 사용자 클라이언트에 실시간으로 알림을 구현했다.
그런데 Vultr 운영서버에 배포하고 보니 알림이 뜨지 않는다. 로컬 개발환경과 운영서버가 다른 점은 로컬에서는 WAS에 바로 접속하고, 운영서버는 Nginx 웹서버를 통해 요청이 프록시 된다. HTTPS도 적용되어 있고...

증상
  • HTTPS 운영 서버에서 WebSocket 기반 알림이 동작하지 않음
  • 브라우저 개발자 도구 Network 탭에 "Provisional headers are shown" 경고 표시
  • wss:// 연결 요청이 응답 없이 실패
원인

원인은 Nginx가 WebSocket 업그레이드 요청에 필요한 HTTP 헤더를 백엔드로 전달하지 않아서였다.

웹소켓은 최초 연결 시 HTTP → WebSocket 프로토콜 업그레이드 핸드셰이크를 수행한다. 이 때 클라이언트는 아래 헤더를 포함해 요청을 보낸다.

text
Upgrade: websocket
Connection: Upgrade

Nginx 기본 설정은 이 헤더를 백엔드로 전달하지 않고 제거하기 때문에, WAS가 업그레이드 요청을 받지 못해 연결이 실패한다.

브라우저는 요청을 전송했으나 응답을 받지 못한 경우 "Provisional headers are shown" 경고를 표시한다.

해결

Nginx 설정에 /ws/ 전용 location 블록을 추가한다.

nginx
location /ws/ {
    proxy_pass http://localhost:8080;
    proxy_http_version 1.1;                    # WebSocket은 HTTP/1.1 필수
    proxy_set_header Upgrade $http_upgrade;    # 업그레이드 헤더 전달
    proxy_set_header Connection "upgrade";     # 커넥션 헤더 전달
    proxy_set_header Host $host;
    proxy_read_timeout 3600s;                  # 유휴 연결 유지 (기본 60s면 끊김)
}

Nginx 서비스를 재시작하고 다시 게시글을 발행해보면...

잘 되었다.
잘 되었다.

핵심 설정 항목
항목 이유
proxy_http_version 1.1 WebSocket은 HTTP/1.1의 keep-alive 기반. 기본값(1.0)으로는 동작하지 않음
proxy_set_header Upgrade $http_upgrade 클라이언트의 Upgrade 헤더를 백엔드로 전달
proxy_set_header Connection "upgrade" Connection 헤더를 upgrade로 고정하여 전달
proxy_read_timeout 3600s 유휴 WebSocket 연결이 기본 60초 타임아웃으로 끊기는 것을 방지
관련 파일
  • notice.js — WebSocket 연결 및 알림 팝업 표시 (/ws/notifications)
  • notice.css — 알림 팝업 스타일
  • web/src/main/java/com/walter/lifelog/web/config/WebSocketConfig.java — WebSocket 엔드포인트 등록
Written by
author
풍우래기

여행을 좋아하는 집돌이 개발자입니다.

블로그에 새로운 글이 발행되었습니다.