Nginx WebSocket 연결: 101 응답 전후를 구분하기

WebSocket이 연결되지 않으면 우선 HTTP handshake가 101에 도달했는지 보세요. 101 이전의 401·403·404·502와 연결 후 일정 시간이 지나 끊기는 현상은 조사할 증거가 다릅니다. 브라우저 콘솔의 오류 한 줄만으로 CORS 설정을 바꾸지 않습니다.

실제로 확인한 헤더 전달 차이

별도 Nginx 1.24.0과 루프백 모의 업스트림을 사용했습니다. 모의 서버는 Upgrade가 websocket이면 101, 없으면 426을 반환하도록 만들었습니다. 같은 요청을 보냈을 때 명시적으로 헤더를 전달한 location은 101, 전달하지 않은 location은 426이었습니다. 이는 헤더 전달 검사이며 완전한 WebSocket 프레임 통신 실험은 아닙니다.

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
# Inside the intended proxy location:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

map은 http 컨텍스트에, 나머지는 의도한 프록시 location에 넣는 조각입니다. 실제 upstream·인증·TLS 설정은 따로 필요합니다. Nginx WebSocket 문서는 hop-by-hop 헤더를 명시적으로 전달하는 이유를 설명합니다. 인증 Origin 검사를 무조건 허용하는 변경은 이 헤더 문제의 해결책이 아닙니다.

101 다음에는 연결 수명과 프레임을 본다

101을 받았어도 앱 메시지 교환과 재연결은 별도입니다. 일정한 간격으로 끊긴다면 프록시의 읽기 timeout, 앱 ping/pong, 중간 네트워크의 유휴 연결 정책을 같은 시간표에 놓습니다. proxy_read_timeout은 전체 세션 길이가 아니라 연속 읽기 사이 대기와 관련됩니다. 값을 크게 늘리는 것보다 실제 heartbeat가 지나가는지 먼저 확인하세요.

수정 전 설정을 보관하고 문법 검사 뒤 해당 location으로 다시 접속합니다. 성공 기준은 handshake와 실제 메시지 왕복, 예상 유휴 시간을 넘긴 연결 유지입니다. 여기서 확인한 101만으로 모바일 백그라운드·Tailscale 경로·실제 앱의 복구 성공을 주장할 수 없습니다.