Search Posts

Visits: 749

NGINXをWebSocket Proxyとして使用する

NGINX as a WebSocket Proxyに従ってセットアップして確認する。
1. node.jsインストール
コマンドラインで次のように入力して、yumでnodejsとnpmをインストールする。

$ sudo yum install nodejs npm

読み込んだプラグイン:priorities, update-motd, upgrade-helper
amzn-main                                                                                   | 2.1 kB  00:00:00     
amzn-updates                                                                                | 2.5 kB  00:00:00     
1143 packages excluded due to repository priority protections
...

2. wsとwscatを使用して設定確認
まず、コマンドラインで次のように入力して、wsをインストールする。

$ sudo npm install ws
npm http GET https://registry.npmjs.org/ws
npm http GET https://registry.npmjs.org/ws
npm http GET https://registry.npmjs.org/ws
npm ERR! Error: UNABLE_TO_GET_ISSUER_CERT_LOCALLY
...

エラーが出たので、NGINXのページにあるコマンドを使用して再実行してみた。

$ sudo npm config set registry http://registry.npmjs.org/
$ sudo npm install ws

npm http GET http://registry.npmjs.org/ws
npm http 200 http://registry.npmjs.org/ws
npm http GET http://registry.npmjs.org/ws/-/ws-7.2.3.tgz
npm http 200 http://registry.npmjs.org/ws/-/ws-7.2.3.tgz
npm WARN engine ws@7.2.3: wanted: {"node":">=8.3.0"} (current: {"node":"v0.10.48","npm":"1.3.6"})
npm http GET http://registry.npmjs.org/bufferutil
npm http GET http://registry.npmjs.org/utf-8-validate
npm http 200 http://registry.npmjs.org/bufferutil
npm http GET http://registry.npmjs.org/bufferutil/-/bufferutil-4.0.1.tgz
npm http 200 http://registry.npmjs.org/utf-8-validate
npm http GET http://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.2.tgz
npm http 200 http://registry.npmjs.org/bufferutil/-/bufferutil-4.0.1.tgz
npm http 200 http://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.2.tgz
npm http GET http://registry.npmjs.org/node-gyp-build
npm http 200 http://registry.npmjs.org/node-gyp-build
npm http GET http://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.7.0.tgz
npm http 200 http://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.7.0.tgz

> utf-8-validate@5.0.2 install /etc/nginx/sites-available/node_modules/utf-8-validate
> node-gyp-build

> bufferutil@4.0.1 install /etc/nginx/sites-available/node_modules/bufferutil
> node-gyp-build

make: ディレクトリ `/etc/nginx/sites-available/node_modules/bufferutil/build' に入ります
make: ディレクトリ `/etc/nginx/sites-available/node_modules/utf-8-validate/build' に入ります
  CC(target) Release/obj.target/bufferutil/src/bufferutil.o
  CC(target) Release/obj.target/validation/src/validation.o
../src/bufferutil.c:3:22: fatal error: node_api.h: そのようなファイルやディレクトリはありません
 #include 

ここでインストール作業を中断し、サーバープログラムを作成する。

[ec2-user@ip-*-*-*-* ~]$ mkdir websocket
[ec2-user@ip-*-*-*-* ~]$ cd websocket
[ec2-user@ip-*-*-*-* websocket]$ vi server.js

server.js

console.log("Server started");
var Msg = '';
var WebSocketServer = require('ws').Server,
    wss = new WebSocketServer({port: 8010});
    wss.on('connection', function(ws) {
        ws.on('message', function(message) {
        console.log('Received from client: %s', message);
        ws.send('Server received from client: ' + message);
    });
});
$ node server.js
Server started

module.js:340
    throw err;
          ^
Error: Cannot find module 'ws'
    at Function.Module._resolveFilename (module.js:338:15)
    at Function.Module._load (module.js:280:25)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object. (/home/ec2-user/websocket/server.js:3:23)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)

wsがインストールできていないのでエラーとなっている。
npmでなく、nvmで再度Amazonの手順に従ってインストールする。

node.jsをAmazon EC2インスタンスにインストール

1. Amazon Elastic Compute Cloud (Amazon EC2) インスタンスにSSHを使用してec2-userで接続する。

2. コマンドラインで次のように入力して、ノードバージョンマネージャ(nvm)をインストールする。
nvmでは、複数のバージョンのnodejsがインストール出来るしバージョン間御切り替えも出来る。

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13226  100 13226    0     0  66462      0 --:--:-- --:--:-- --:--:-- 66462
=> Downloading nvm from git to '/home/ec2-user/.nvm'
=> Cloning into '/home/ec2-user/.nvm'...
remote: Enumerating objects: 278, done.
remote: Counting objects: 100% (278/278), done.
remote: Compressing objects: 100% (245/245), done.
remote: Total 278 (delta 32), reused 95 (delta 20), pack-reused 0
Receiving objects: 100% (278/278), 142.15 KiB | 443.00 KiB/s, done.
Resolving deltas: 100% (32/32), done.
=> Compressing and cleaning up git repository

=> Appending nvm source string to /home/ec2-user/.bashrc
=> Appending bash_completion source string to /home/ec2-user/.bashrc
=> You currently have modules installed globally with npm. These will no
=> longer be linked to the active version of Node when you install a new node
=> with nvm; and they may (depending on how you construct your $PATH)
=> override the binaries of modules installed with nvm:
=> If you wish to uninstall them at a later point (or re-install them under your
=> nvm Nodes), you can remove them from the system Node as follows:

     $ nvm use system
     $ npm uninstall -g a_module

=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

3. コマンドラインで次のように入力して、nvmを有効にする。

. ~/.nvm/nvm.sh

4. コマンドラインで次のように入力して、最新のnode.jsをインストールする。

nvm install node

Downloading and installing node v13.12.0...
Downloading https://nodejs.org/dist/v13.12.0/node-v13.12.0-linux-x64.tar.xz...
######################################################################### 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v13.12.0 (npm v6.14.4)
Creating default alias: default -> node (-> v13.12.0)

node.jsをインストールするとnpm(Node Package Manager)もインストールされるので必要に応じて追加モジュールのインストールが可能。

5. 正常にインストールされたか、コマンドラインで次のように入力して確認する。

node -e "console.log('Running Node.js ' + process.version)"

組み込まれたnode.jsのバージョンが次のようなメッセージで表示される。

Running Node.js v13.12.0

参考:https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers

wsをWebSocketサーバー用にインストールする

コマンドラインで次のように入力してwsをインストールする。

$ sudo npm install ws
npm WARN package.json websockets@1.0.0 No description
npm WARN package.json websockets@1.0.0 No repository field.
npm WARN package.json websockets@1.0.0 No README data
npm http GET http://registry.npmjs.org/ws/-/ws-1.1.5.tgz
npm http 200 http://registry.npmjs.org/ws/-/ws-1.1.5.tgz
npm http GET http://registry.npmjs.org/ultron
npm http GET http://registry.npmjs.org/options
npm http 200 http://registry.npmjs.org/options
npm http 200 http://registry.npmjs.org/ultron
npm http GET http://registry.npmjs.org/options/-/options-0.0.6.tgz
npm http GET http://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz
npm http 200 http://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz
npm http 200 http://registry.npmjs.org/options/-/options-0.0.6.tgz
ws@1.1.5 node_modules/ws
├── options@0.0.6
└── ultron@1.0.2

wscatをWebSocketクライアントとして使用する

コマンドラインで次のように入力してwscatをインストールする。

$ npm install -g wscat
/home/ec2-user/.nvm/versions/node/v13.12.0/bin/wscat -> /home/ec2-user/.nvm/versions/node/v13.12.0/lib/node_modules/wscat/bin/wscat
+ wscat@4.0.0
added 11 packages from 8 contributors in 1.243s

Nginx設定と確認

接続をHTTPからWebSocketにUpgradeするために使用されるHTTPは、UpgradeおよびConnectionヘッダーを使用する。NginxがリバースプロキシーサーバーとしてWebSocketをサポートするとき、次の課題がある。a)WebSocketがhop‑by‑hopプロトコルであるため、プロキシサーバーがクライアントからのUpgrade要求を仲介するとき、適切なヘッダーを含めて、独自のUpgrade要求をバックエンドサーバーに送信する必要がある。b)HTTPで使用される一般的な短い接続とは異なり、WebSocketの接続は継続した接続であるため、リバースプロキシはこれらの接続を開いたままにする必要がある。
NGINXは、クライアントとバックエンドサーバーの間にトンネルを設定できるようにすることで、WebSocketをサポートしている。 NGINXがクライアントからバックエンドサーバーにアップグレードリクエストを送信するには、次の例のように、UpgradeヘッダーとConnectionヘッダーを明示的に設定する必要がある。
リクエストのUpgradeヘッダーが ”に設定されている場合にConnectionヘッダーがclose設定されるように、mapブロックを追加している。

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }
 
    upstream websocket {
        server 127.0.0.1:8010;
    }
 
    server {

        location / {
            proxy_pass http://websocket;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header Host $host;
        }
    }
}

サーバーのserver.jsとクライアントのwscat間の通信を確認する。

サーバー クライアント
$ node server.js
Server started
Received from client: Hello
Received from client: How are you
$ wscat –connect ws://127.0.0.1:8010
Connected (press CTRL+C to quit)
> Hello
< Server received from client: Hello > How are you
< Server received from client: How are you