websocket_railsのaws ec2環境での通信設定

railsでwebsocketを使用する場合、websocket_railsという便利なgemがあります。
これを使ってみましたが、awsのcentosの本番環境での通信設定に半日ぐらい要してしまいました。
少しややっこしいので、手順等、残しておきます。

## ローカル接続確認
まずはローカルでのwebsocket_railsの接続確認。

Gemfileに gem ‘websocket-rails’を追記して、bundle installを実行。

```ruby:Gemfile追記
gem 'thin'
gem 'websocket-rails', github: 'moaa/websocket-rails', branch: 'sync_fixes'
gem 'redis', '3.2.0'
```

次にwebsocket-railsに必要なファイルをgenerate。

```
rails g websocket_rails:install
```

以下のファイルがgenerateされる。

* config/events.rb
railsのroutes.rbような物。websocketのイベントのマッピングで使用します。

* config/initializers/websocket_raiils.rb
websocket_raiilsのセットアップ用。

* app/assets/javascripts/application.js
websocket_railsに必要な
//= require websocket_rails/main
が追記される


websocket確認用のサンプルで下記のような簡単なをhtml作成

```html:html
<div ng-view="" class="ng-scope">
<textarea rows="5" style="width: 50%;" ng-model="testMsg" class="ng-valid ng-scope ng-dirty ng-valid-parse ng-touched"></textarea>
<br class="ng-scope">
<button type="button" class="btn btn-default ng-scope" ng-click="testSend()">送 信/button>
<br class="ng-scope">
<label class="ng-scope">受信メッセージ</label>
<br class="ng-scope">
<p ng-bind="reciveModel.reciveMsg" class="ng-binding ng-scope"></p>
<label class="ng-scope">入力内容</label>
<br class="ng-scope">
<p ng-bind="testMsg" class="ng-binding ng-scope"></p>
</div>
```

![スクリーンショット 2015-08-04 9.26.39.png](https://qiita-image-store.s3.amazonaws.com/0/17388/8da63b49-b5bd-3154-5333-d7509f6e531f.png)

javascriptにWebSocketRailsの接続、送信、受信処理を記述

```js:angularjsを使用
// WebSocketRailsが初期化されてないければ初期化して接続
if ($rootScope.wsRails == undefined ||
    $rootScope.wsRails == null) {
  try {
    $rootScope.wsRails = new WebSocketRails("127.0.0.1:3001/websocket");		
  } catch (e) {
    alert("error");
  }
};

// websocketの受信イベントのバインド
$rootScope.wsRails.unbind();
$rootScope.wsRails.bind("websocket_chat", function(message){
  $scope.reciveModel.reciveMsg = message;
  $scope.$apply();
});

// テスト送信処理
$scope.testSend = function() {
  $rootScope.wsRails.trigger("websocket_chat", $scope.testMsg);
};
```

config/events.rbに「websocket_chat」イベントのマッピングを設定。

```ruby:events.rb
subscribe :websocket_chat, to: WebsocketChatController, with_method: :message_recieve
```

railsのコントローラーにwebsocket_chat_controller.rbを追加

```ruby:websocket_chat_controller.rb
class WebsocketChatController < WebsocketRails::BaseController
  def message_recieve
    # クライアントからのメッセージを取得
    recieve_message = message()
    
    # websocket_chatイベントで接続しているクライアントにブロードキャスト
    broadcast_message(:websocket_chat, recieve_message)
  end
end
```

ここまでやってrailsを起動しても、下記のようなエラーが出る。

```
/Users/qq/Documents/workspace/fesny/vendor/bundle/ruby/2.0.0/gems/redis-3.2.0/lib/redis/client.rb:320:in `rescue in establish_connection': Error con
necting to Redis on localhost:6379 (ECONNREFUSED) (Redis::CannotConnectError)
```

Redisに繋がらないといっているので、osxにRedisを入れます。

Homebrewを利用してインストール

```
brew install redis
```

起動

```
 redis-server /usr/local/etc/redis.conf
```

接続確認

```
redis-cli
```

Redisをインストール、起動した後にrailsを起動すると、正常に起動。
だけど、websocketの接続に失敗している。

```
WebSocket connection to 'ws://127.0.0.1:3001/websocket' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
```

なぜかなあと調べていたところ、githubのwebsocket-railsにStandalone-Server-Modeで起動せよという記述を発見。
https://github.com/websocket-rails/websocket-rails/wiki/Standalone-Server-Mode

thinで開発環境でやる場合でもStandalone-Server-Modeでやらないといけないのだろうか？
よく分からないが実行してみる事に。。

config/initializers/websocket_rails.rbを下記設定に変更。

```ruby:websocket_rails.rb
  config.standalone = true
  config.standalone_port = 3001
  config.redis_options = {driver: :ruby}
  config.synchronize = false
  config.redis_options = {:host => 'localhost', :port => '6379'}
```

websocket_railsの起動

```
sudo rake websocket_rails:start_server
```

websocket_railsの停止

```
sudo rake websocket_rails:stop_server
```

websocket_railsの起動確認

```
ps aux | grep websocket
root            6703   2.4  2.2  3125404  93444   ??  S    10:09AM   0:04.89 thin server (0.0.0.0:3001) [websocket_rails]  
```

websocket_railsが起動している状態で、動かしてみると、WebSocketが正常に動いた。

この後、本番環境でも確認してみる事に。
本番でうまく環境構築できなければ、開発が無駄になってしまうので。。


## 本番接続確認

本番環境はaws ec2でcentos用のディストリビューションを使用し、OSバージョンは7.1で、webサーバーはnginxです。
すでにrailsの別のプロダクトで運用中の為、バーチャルドメインで配置して、railsもデプロイします。

その後、redisが入っていない為、yumインストール

```
yum install redis
```

redisの起動

```
systemctl start redis
```

接続確認

```
redis-cli
```

railsの起動(unicorn)、websocket_railsの起動を行う。
特にエラーは発生せず、ログの「log/websocket_rails_server.log」、「log/websocket_rails.log」にもエラーははかれていない。
しかし、javascriptのwebscoketの接続部分でエラーが発生している。
ここから半日ぐらいハマりました。

まずjavascriptのサーバーのIPが127.0.0.1のままになっていたので、修正。

```js
$rootScope.wsRails = new WebSocketRails("サーバーIP:3001/websocket");
```

次にawsのインバウンドポートの3001を開ける。
これでもまだ接続エラー。

ポートをサーバーサイドで確認すると3001はthinが待ち受けしている模様。

```
netstat -tanp
tcp        0      0 0.0.0.0:3001            0.0.0.0:*               LISTEN      21787/thin server ( 
```

クライアントからとサーバーからでtelnetで確認してみるが接続できる。

```
telnet 127.0.0.1 3001
telnet サーバーIP 3001
```

ここで、もしかしてnginxでproxyしないといけないのかと思い、nginxのconfに下記を追記。

```
upstream yeomanserver {
        server 127.0.0.1:3001;
}
```

```
    location /websocket {
        proxy_pass http://yeomanserver;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
```

nginxは80番ポートで待ち受けているので、javascriptの3001ポートの使用部分を削除。

```js
$rootScope.wsRails = new WebSocketRails("サーバーIP/websocket");
```

ここまでやっても接続できない。
log/production.logを見ても何もログは出力されていないもよう。
3001ポートでの待ち受けはしているはず。
websocket_railを止めて、実行するとエラー内容が変わる為、nginxはthinと連携でなんらかのエラーが起こっている？
その後、いくらくぐってもそれらしい情報は出てこず。
途方にくれそうになった時にブラウザに何の気無しに下記を入力。

```
http://サーバーIP:3001
```

するとMySQLとの接続が失敗したとメッセージが出る。
rails(unicorn)の起動は成功しているし、実行ページのブラウザ表示も問題ない。
接続失敗のユーザー名をみるとどうやらdevelopmentモードで起動しているもよう。

websocket_railsの起動もproductionモードの指定ができるようなので、下記コマンドで起動。

```
sudo rake websocket_rails:start_server export RAILS_ENV="production"
```

## 最後に
その後、本番環境でもWebSocketは正常につながり、送受信も正常に動きました。
websocket_railsでもhttpで接続したら、普通のrailsと同じような動作をするんですね。
しょうもない問題ですが、半日ぐらいはまったので、備忘録として残しておきます。


<br>

> 参考
[Railsで複数グループ対応のチャットアプリを作ってみた](http://altarf.net/computer/rails/2502)
[github websocket-rails](https://github.com/websocket-rails/websocket-rails)
[github websocket-rails issues 211](https://github.com/websocket-rails/websocket-rails/issues/211)
[MacにRedisをインストールする](http://qiita.com/checkpoint/items/58b9b0193c0c46400eeb)