Rails
nginx
capistrano
websocket
puma

Rails5のActionCableをCapistrano経由でデプロイ

More than 3 years have passed since last update.

Rails 5の目玉機能の一つに、WebSocketsを容易に利用できるActionCableがあります。Rails 4でもgemで提供されてましたが、Rails 5で本体にマージされました。しかし本番環境の情報が少なかったので、記事にまとめました。ActionCableを使ったRails 5アプリは、以下の記事がわかりやすいです。

この例ではdevelopment環境およびHerokuでは動作しますが、この記事は本番環境のnginxを自前で設定してゆきます。


動作環境と構成

フロントのWebサーバにはnginxを、RackサーバにはPumaを使い、Capistrano3でデプロイします。UnicornをRackサーバに使うと、WebSocketsサーバも別に作成する必要があるので、今回はPumaを使います。Pumaとnginxの処理は puma.sock 経由で行います。デプロイおよびPumaの制御にはCapistranoを使います。サービスとして起動するには、jungleまたはsystemdの設定を自前で用意すれば良さそうですが、ここでは触れません。

ActionCableのデフォルトに従い/cableをWebSocketsのパスに、つまりws://your-domain.example.com/cable(またはwss://your-domain.example.com/cable)からWebSocketsに接続します。


Railsアプリの設定

まずRailsアプリ側で、ActionCableが許可するホストを設定します。nginxとRailsアプリが同サーバ上でも、サーバのホストを許可する必要があります(Allowed Request Origins)。


config/environments/production.rb

config.action_cable.allowed_request_origins = [ 'https://your-domain.example.com' ]



Capistranoの設定とデプロイ

capistrano-pumaというgemを使うと、サーバ側のpumaを手元から制御できます。Gemfilecapistrano3-pumacapistrano-puma は別のgemないので注意!)を追加して、Capfile に設定します。


Gemfile

gem 'capistrano3-puma' , group: :development



Capfile

require 'capistrano/puma'


以上でCapistrano経由で本番環境のpumaを制御できます。

(bundle exec) cap production puma:start

この時 puma:config タスクが走り、pumaの設定ファイルがデプロイ先の "#{shared_path}/puma.rb" に作成されます。pumaの設定ファイルは config/deploy.rb を元に生成されます。設定項目はcapistrano-pumaのREADMEにあります。デフォルトでは、pumaのsockファイルが "#{shared_path}/tmp/sockets/puma.sock" に配置されます。つまり puma:start を走らせると"#{shared_path}/tmp/sockets/puma.sock" 越しにRailsアプリにアクセスできるので、nginxはこのファイルを見に行くよう設定します。


nginxの設定

通常のHTTPリクエストは、Unicorn同様upstreamにソケットを指定します。WebSocketsに対するリクエスト(/cable)はHTTPバージョンとヘッダを書き換えて同じソケットに渡します。


nginx.conf

http {

upstream puma {
server unix:/path-to-your-project/tmp/sockets/puma.sock;
}

server {
# General web access
try_files $uri $uri/index.html $uri.html @webapp;
location @webapp {
root /path-to-your-project/public/;
proxy_pass http://puma;
}

# WebSocket configure
location /cable {
proxy_pass http://puma;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}



繋がらないときは

検証用にcURLでWebSockets通信もできますが、wscatが便利です。

wscat -c ws://your-domain.example.com/cable    # or wss://... in SSL version

設定ができてなければエラーが帰ってきて、反応が無いときは正常に通信できてる場合が多いです。正しく通信できないときはログとにらめっこしましょう。


参考