WebSocket プロキシ

HTTP/1.1からWebSocketへのクライアントとサーバー間の接続を切り替えるには、HTTP/1.1で利用可能なプロトコルスイッチメカニズムを使用します。

ただし、少し注意が必要です。つまり、"Upgrade"はホップバイホップヘッダーなので、クライアントからプロキシサーバーに渡されることはありません。フォワードプロキシの場合、クライアントはCONNECTメソッドを使用してこの問題を回避できます。ただし、これはリバースプロキシでは機能しません。クライアントはプロキシサーバーの存在を認識していないため、プロキシサーバー上で特別な処理が必要になります。

バージョン1.3.13以降、nginxは、プロキシサーバーがコード101(Switching Protocols)のレスポンスを返し、クライアントがリクエストで"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 pingフレームを送信するように構成して、タイムアウトをリセットし、接続がまだアクティブかどうかを確認できます。