WebSocketのプロキシ
クライアントとサーバの間の接続を、HTTP/1.1からWebSocketに変えるには、HTTP/1.1で利用可能なprotocol switchメカニズムを使います。
しかしながら一つ微妙な考えがあります: "Upgrade"はhop-by-hop ヘッダであり、クライアントからプロキシされるサーバへは渡されないからです。フォワードプロキシを使って、クライアントはこの問題を回避するためにCONNECT
メソッドを使うかもしれません。しかしこれはリバースプロキシの場合に動作しません。というのはクライアントはプロキシサーバに気づかずに、プロキシサーバでの特別な処理が必要になるからです。
バージョン 1.3.13から、プロキシされたサーバがコード101(Switching protocols)を返した場合に、nginxはクライアントとプロキシされたサーバの間でトンネルを設定することができる特別なモードの操作を実装しています。クライアントはリクエストの"Upgrade"ヘッダを経由してプロトコルを切り替えるように依頼します。
上で述べたように、"Upgrade" と "Connection" を含む hop-by-hopヘッダはクライアントからプロキシされるサーバへ渡されないため、プロキシされるサーバがクライアントのプロトコルを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フレームを送信するように設定することができます。