ブログ | NGINX

WebSocket プロキシとしての NGINX

NGINX-F5 水平黒タイプ RGB の一部
リック・ネルソン サムネイル
リック・ネルソン
2014 年 5 月 16 日公開

WebSocketプロトコルは、クライアントとサーバー間のリアルタイムの双方向通信をサポートする Web アプリケーションを作成する方法を提供します。 HTML5 の一部である WebSocket を使用すると、これまでの方法よりもこれらのタイプのアプリケーションの開発がはるかに簡単になります。 Chrome、Firefox、Internet Explorer、Opera、Safari など、ほとんどの最新ブラウザは WebSocket をサポートしており、サーバー アプリケーション フレームワークも WebSocket をサポートするようになっています。

パフォーマンスと高可用性のために複数の WebSocket サーバーが必要なエンタープライズの本番環境では、WebSocket プロトコルを理解する負荷分散レイヤーが必要です。NGINX はバージョン 1.3 以降で WebSocket をサポートしており、リバース プロキシとして機能し、WebSocket アプリケーションの負荷分散を行うことができます。 (NGINX Plus のすべてのリリースでは WebSocket もサポートされています。)

WebSocket 接続の負荷分散を行う NGINX のスケーラビリティに関する最新のパフォーマンス テストを確認してください。

WebSocket プロトコルは HTTP プロトコルとは異なりますが、WebSocket ハンドシェイクは HTTP と互換性があり、HTTP アップグレード機能を使用して接続を HTTP から WebSocket にアップグレードします。 これにより、WebSocket アプリケーションを既存のインフラストラクチャに簡単に適合させることができます。 たとえば、WebSocket アプリケーションは標準の HTTP ポート 80 と 443 を使用できるため、既存のファイアウォール ルールを使用できます。

WebSocket アプリケーションは、クライアントとサーバー間の接続を長時間開いたままにし、リアルタイム アプリケーションの開発を容易にします。 HTTP から WebSocket への接続をアップグレードするために使用される HTTP アップグレード メカニズムは、 UpgradeヘッダーとConnectionヘッダーを使用します。 リバース プロキシ サーバーが WebSocket をサポートする際に直面する課題がいくつかあります。 1 つは、WebSocket はホップバイホップ プロトコルであるため、プロキシ サーバーがクライアントからのアップグレード要求をインターセプトすると、適切なヘッダーを含む独自のアップグレード要求をバックエンド サーバーに送信する必要があることです。 また、WebSocket 接続は、HTTP で使用される一般的な短命な接続とは対照的に、長命であるため、リバース プロキシは、これらの接続がアイドル状態であるように見えるという理由で閉じるのではなく、開いたままにしておく必要があります。

NGINX は、クライアントとバックエンド サーバーの間でトンネルを設定できるようにすることで WebSocket をサポートします。 NGINX がクライアントからバックエンド サーバーにアップグレード要求を送信するには、次の例のように、 Upgrade ヘッダーConnectionヘッダーを明示的に設定する必要があります。

location /wsapp/ { proxy_pass http://wsbackend;
proxy_http_version 1.1;
proxy_set_header アップグレード $http_upgrade;
proxy_set_header 接続 "アップグレード";
proxy_set_header ホスト $host;
}

これが完了すると、NGINX はこれを WebSocket 接続として処理します。

NGINX WebSocket の例

これは、NGINX が WebSocket プロキシとして動作することを示すライブ例です。 この例では、 Node.js上に構築された WebSocket 実装であるwsを使用します。 NGINX は、 wsと Node.js を利用するシンプルな WebSocket アプリケーションのリバース プロキシとして機能します。 これらの手順は Ubuntu 13.10 および CentOS 6.5 でテストされていますが、他の OS やバージョンでは調整が必要になる可能性があります。 この例では、WebSocket サーバーの IP アドレスは 192.168.100.10 で、NGINX サーバーの IP アドレスは 192.168.100.20 です。

  1. Node.js と npm がまだインストールされていない場合は、次のコマンドを実行します。

    • Debian および Ubuntu の場合:

      $ sudo apt-get で nodejs npm をインストールします
    • RHEL および CentOS の場合:

      $ sudo yum インストール nodejs npm
  2. Node.js は、Ubuntu ではnodejsとして、CentOS ではnodeとしてインストールされます。 この例ではnodeを使用しているため、Ubuntu ではnodejsからnodeへのシンボリック リンクを作成する必要があります。

    $ ln -s /usr/bin/nodejs /usr/local/bin/node
  3. ws をインストールするには、次のコマンドを実行します。

    $ sudo npm インストール ws

    注記: エラーメッセージが表示された場合: 「エラー: レジストリからの取得に失敗しました: ws」という問題を解決するには、次のコマンドを実行します。

    $ sudo npm config レジストリを設定します http://registry.npmjs.org/

    次に、 sudo npm install wsコマンドを再度実行します。

  4. ws には、クライアントに使用するプログラム/root/node_modules/ws/bin/wscatが付属していますが、サーバーとして機能するプログラムを作成する必要があります。 次の内容を含むserver.jsというファイルを作成します。

    console.log("サーバーが起動しました");
    var Msg = '';
    var WebSocketServer = require('ws').Server
    , wss = new WebSocketServer({port: 8010});
    wss.on('connection', function(ws) {
    ws.on('message', function(message) {
    console.log('クライアントから受信: %s', message);
    ws.send('サーバーがクライアントから受信: ' + message);
    });
    });
  5. サーバー プログラムを実行するには、次のコマンドを実行します。
    $ノードサーバー.js
  6. サーバーは最初の「サーバーが起動しました」というメッセージを出力し、ポート 8010 でリッスンして、クライアントが接続するのを待機します。 クライアント要求を受信すると、それをエコーし、受信したメッセージを含むメッセージをクライアントに送り返します。 NGINX がこれらのリクエストをプロキシするようにするには、次の構成を作成します。 リクエスト内のUpgradeヘッダーが''に設定されている場合に、 Connectionヘッダーが正しくcloseに設定されるように、マップブロックを追加します。

    http {
    map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
    }
    
    アップストリーム websocket {
    server 192.168.100.10:8010;
    }
    
    server {
    listen 8020;
    location / {
    proxy_pass http://websocket;
    proxy_http_version 1.1;
    proxy_set_header アップグレード $http_upgrade;
    proxy_set_header 接続 $connection_upgrade;
    proxy_set_header ホスト $host;
    }
    }
    }

    NGINX はポート 8020 をリッスンし、リクエストをバックエンドの WebSocket サーバーにプロキシします。 proxy_set_headerディレクティブにより、NGINX は WebSocket プロトコルを適切に処理できるようになります。

  7. サーバーをテストするには、クライアントとしてwscat を実行します。

    $ /root/node_modules/ws/bin/wscat --connect ws://192.168.100.20:8020

    wscat は、 NGINX プロキシを介して WebSocket サーバーに接続します。 wscat がサーバーに送信するメッセージを入力すると、そのメッセージがサーバー上でエコーされ、その後、サーバーからのメッセージがクライアントに表示されます。 サンプルのやり取りは次のとおりです。

    サーバ: クライアント:
    $ノードサーバー.js
    サーバーを起動しました
     
     
     
     
     
    wscat --connect ws://192.168.100.20:8020
    接続しました(終了するには CTRL+C を押してください)
    > こんにちは
    クライアントから受信: こんにちは
    < サーバーがクライアントから受信: こんにちは

    ここでは、クライアントとサーバーがプロキシとして機能している NGINX を介して通信でき、クライアントまたはサーバーのいずれかが切断されるまでメッセージを送受信し続けることができることがわかります。 NGINX で WebSocket を適切に処理するために必要なことは、接続を HTTP から WebSocket にアップグレードするアップグレード要求を処理するようにヘッダーを正しく設定することだけです。

さらに読む


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"