WebSocket 프록시

클라이언트와 서버 간 연결을 HTTP/1.1에서 WebSocket으로 전환하려면 HTTP/1.1에서 제공하는 프로토콜 전환 메커니즘을 사용합니다.

하지만 한 가지 미묘한 부분이 있습니다. “Upgrade”는 홉 바이 홉 헤더이므로 클라이언트에서 프록시된 서버로 전달되지 않습니다. 정방향 프록시의 경우, 클라이언트는 CONNECT 메서드를 사용해서 이 문제를 우회합니다. 하지만 역방향 프록시에서는 클라이언트가 프록시 서버를 인식하지 못하므로 이 방법을 사용할 수 없어 프록시 서버에서 특수한 처리가 필요합니다.

1.3.13버전부터 nginx는 특수한 작업 모드가 구현되어서, 프록시된 서버가 101 코드(프로토콜 전환)를 포함한 응답을 반환하고 클라이언트가 요청에서 “Upgrade” 헤더를 통해 프로토콜 전환을 요청한 경우 클라이언트와 프록시된 서버 사이에 터널을 설정할 수 있습니다.

앞서 설명한 바와 같이, “Upgrade” 및 “Connection”을 포함한 홉 바이 홉 헤더는 클라이언트에서 프록시된 서버로 전달되지 않으므로 프록시된 서버에서 클라이언트가 WebSocket으로 프로토콜을 전환하려는 것을 알아내려면 이 헤더들을 명시적으로 전달해야 합니다.

location /chat/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

좀 더 복잡한 예시에서는 프록시된 서버로 보내는 요청의 “Connection” 헤더 필드 값은 클라이언트 요청 헤더에 “Upgrade” 필드가 있는지에 따라 달라집니다.

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {
        ...

        location /chat/ {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }

기본적으로 프록시된 서버가 60초 이내로 데이터를 전송하지 않으면 연결이 닫힙니다. 이 시간제한은 proxy_read_timeout 명령을 사용하여 늘릴 수 있습니다. 또는, 프록시된 서버는 WebSocket 핑 프레임을 규칙적으로 보내서 시간제한을 재설정하고 연결이 아직 활성 상태인지 검사하도록 구성할 수 있습니다.