web-dev-qa-db-ja.com

nginxをバックエンドWebSocketサーバーのリバースプロキシとして使用できますか?

Ruby on Railsアプリで、html5 WebSocketを利用する必要があります。現在、2つの別々の「サーバー」があります。話す:nginx + Passengerで実行されているメインアプリと、Pratik Naikの Cramp フレームワーク( Thin で実行されている)を使用してWebSocket接続を処理する別のサーバー。

理想的には、デプロイの時期になると、Railsアプリがnginx + Passengerで実行され、WebSocketサーバーがnginxの背後にプロキシされるため、別のポートで実行されているWebSocketサーバー。

問題は、このセットアップでは、nginxがThinへの接続を早く閉じているように見えることです。シンサーバーへの接続は正常に確立され、200応答コードですぐに閉じられます。私たちの推測では、nginxは、クライアントがWebSocketトラフィックの長時間実行接続を確立しようとしていることを認識していません。

確かに、私はnginx configに精通しているわけではないので、WebSocketサーバーのリバースプロキシとして機能するようにnginxを構成することも可能ですか?または、nginxが新しいWebSocketハンドシェイクのサポートを提供するのを待つ必要がありますか?アプリサーバーとWebSocketサーバーの両方がポート80でリッスンする必要があるとすると、今のところnginxを使用せずにThinを別のサーバーで実行する必要があるのでしょうか。

アドバイスや提案を事前に感謝します。 :)

-ジョン

35
John Reilly

現在、これにnginxを使用することはできません[もう真実ではない]、しかし私はHAProxyを見ることをお勧めします。私はまさにこの目的のためにそれを使用しました。

トリックは、ソケット接続が閉じられないように長いタイムアウトを設定することです。何かのようなもの:

timeout client  86400000 # In the frontend
timeout server  86400000 # In the backend

同じポートでRailsとクランプアプリケーションを提供する場合は、ACLルールを使用してWebSocket接続を検出し、別のバックエンドを使用できます。したがって、haproxyフロントエンド構成は次のようになります。

frontend all 0.0.0.0:80
  timeout client    86400000
  default_backend   Rails_backend
  acl websocket hdr(Upgrade)    -i WebSocket
  use_backend   cramp_backend   if websocket

完全を期すために、バックエンドは次のようになります。

backend cramp_backend
  timeout server  86400000
  server cramp1 localhost:8090 maxconn 200 check
26
mloughran

nginx_tcp_proxy_module module を使用してみませんか?

このモジュールは、Nginxを使用した一般的なTCPプロキシ用に設計されています。WebSocketにも適していると思います。開発ブランチにtcp_ssl_moduleを追加するだけです。

12
yaoweibin

nginx(> = 1.3.13)がサポートするようになりました WebSocketのリバースプロキシ。

# the upstream server doesn't need a prefix! 
# no need for wss:// or http:// because nginx will upgrade to http1.1 in the config below
upstream app_server {
    server localhost:3000;
}

server {
    # ...

    location / {
        proxy_pass http://app_server;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $Host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_redirect off;
    }
}
11
mak

箱から出して(つまり公式ソース)Nginxはアップストリーム(=バックエンド)へのHTTP 1.0接続のみを確立できます。つまり、キープアライブは不可能です。Nginxはアップストリームサーバーを選択し、サーバーへの接続、プロキシ、キャッシュを開きます(必要な場合) )接続を閉じます。それでおしまい。

これが、バックエンドへの永続的な接続を必要とするフレームワークがNginxを介して機能しない根本的な理由です(HTTP/1.1 =キープアライブなし、WebSocketなし)。この欠点があるにもかかわらず、明らかな利点があります。Nginxは、いくつかのアップストリーム(ロードバランス)から選択し、それらのいくつかが失敗した場合に、生きているものにフェイルオーバーできます。

編集:バージョン1.1.4以降、Nginxはバックエンドとキープアライブに対してHTTP1.1をサポートしています。 「fastcgi」および「proxy」アップストリームがサポートされています。 ここにドキュメントがあります

7

同じ問題について疑問に思っている人のために、nginxはHTTP1.1アップストリームを公式にサポートするようになりました。 「keepalive」および「proxy_http_version1.1」については、nginxのドキュメントを参照してください。

5

新しいHTTPプッシュモジュールを使用したNginxはどうですか: http://pushmodule.slact.net/ 。リバースプロキシで心配しなければならないかもしれない接続ジャグリング(いわば)を処理します。これは確かに、まだ完全にはミックスされていないWebsocketの実行可能な代替手段です。 HTTPプッシュモジュールの開発者はまだ完全に安定したバージョンに取り組んでいることを知っていますが、活発に開発中です。本番コードベースで使用されているバージョンがあります。著者の言葉を引用すると、「退屈な名前の便利なツール」です。

3
Eric Lubow

私はnginxを使用して、長いポーリング接続を備えたコメットスタイルのサーバーにリバースプロキシします。これはうまく機能します。 proxy_send_timeoutとproxy_read_timeoutを適切な値に設定してください。また、nginxのプロキシモジュールはまだhttp 1.1をサポートしていないと思うので、nginxがプロキシしているバックエンドサーバーがhttp1.0をサポートしていることを確認してください。

いくつかの回答の混乱を解消するために、キープアライブを使用すると、クライアントは接続を再利用して別のHTTPリクエストを送信できます。元の質問が尋ねていたイベントが発生するまで、長いポーリングや接続を開いたままにすることとは何の関係もありません。したがって、nginxのプロキシモジュールがキープアライブを持たないHTTP1.0のみをサポートすることは問題ではありません。

2
Mark Maunder