Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure ActionCable with Nginx and Unicorn in production?

I've recently switched my rails project from Rails4 to 5.0.0.beta3 to use the awesome ActionCable.

My ActionCable server is run inside unicorn. In development all works fine. In production I have

Started GET "/cable" for xxx.xxx.xxx.xxx at 2016-03-28 18:06:38 +0300
Started GET "/cable/" [WebSocket] for xxx.xxx.xxx.xxx at 2016-03-28 18:06
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
Registered connection (189772ff-6229-48f1-ae7f-d9a96ad3a6c3)
Finished "/cable/" [WebSocket] for xxx.xxx.xxx.xxx at 2016-03-28 18:06:35

And this message repeats again and again in a loop.

I've tried a lot of options at stackoverflow to handle this but nothing helps. My nginx config:

 upstream unicorn {
   server unix:/tmp/unicorn.my_app.sock fail_timeout=0;
 }

 server {
   server_name www.my_app.com;
   return 301 $scheme://my_app.com$request_uri;
 }

 server {
   listen 80 default deferred;
   server_name my_app.com;
   root /var/www/my_app/current/public;

   location ^~ /assets/ {
     gzip_static on;
     expires max;
     add_header Cache-Control public;
   }

   try_files $uri/index.html $uri @unicorn;
   location @unicorn {
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header Host $http_host;
     proxy_redirect off;
     proxy_pass http://unicorn;
   }

   location /cable {
     proxy_pass http://unicorn/cable;
     proxy_http_version 1.1;
     proxy_set_header Upgrade websocket;
     proxy_set_header Connection Upgrade;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }

   error_page 500 502 503 504 /500.html;
   keepalive_timeout 5;
 }

To be sure that request is allowed I've temporarily use this code in initializers: ActionCable.server.config.disable_request_forgery_protection = true

My cable.coffee file

 @App ||= {}
 App.cable = ActionCable.createConsumer "/cable"

My config/cable.yml file

production:
 adapter: redis
 url: redis://localhost:6379/1

I'm not so experienced at this question, so any help would be great.

like image 948
yzalavin Avatar asked Mar 28 '16 09:03

yzalavin


3 Answers

This is config that I use for my website, and it seems to be working fine (Rails 5 + Nginx + Unicorn + Capistrano). Includes you see in the snippet are from h5bp/server-configs-nginx, but I don't think they could be a reason why your configuration does not work.

upstream example_app {
  server unix:/home/username/www/example.com/current/tmp/sockets/unicorn.example.com.sock fail_timeout=0;
}

server {
  listen 80;
  server_name example.com www.example.com;

  return 301 https://example.com$request_uri;
}

server {
  listen 443 ssl;
  server_name www.example.com;

  include h5bp/directive-only/ssl.conf;
  ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;

  return 301 https://example.com$request_uri;
}

server {
  listen 443 ssl;
  server_name example.com;

  include h5bp/directive-only/ssl.conf;
  ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;

  root /home/username/www/example.com/current/public;

  # Set maximum request body size for uploads
  client_max_body_size 25m;

  try_files $uri/index.html $uri @unicorn;
  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;
    proxy_pass http://example_app;
  }

  location /cable {
    proxy_pass http://example_app;
    proxy_http_version 1.1;
    proxy_set_header Upgrade websocket;
    proxy_set_header Connection Upgrade;

    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;
  }

  access_log /var/log/nginx/example.com/access.log;
  error_log /var/log/nginx/example.com/error.log;

  charset utf-8;
  server_tokens off;

  error_page 404 /404.html;

  include h5bp/basic.conf;
}

cable.yml

production:
  adapter: redis
  url: redis://localhost:6379/1

cable.js

//= require action_cable
//= require_self
//= require_tree ./channels

(function() {
  this.App || (this.App = {});

  App.cable = ActionCable.createConsumer();

}).call(this);
like image 102
Rolandas Barysas Avatar answered Dec 04 '22 19:12

Rolandas Barysas


In the location /cable section need to add a line proxy_set_header Host $http_host;

Should be:

location /cable {
     proxy_pass http://unicorn/cable;
     proxy_http_version 1.1;
     proxy_set_header Upgrade websocket;
     proxy_set_header Connection Upgrade;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header Host $http_host;
   }
like image 41
askrynnikov Avatar answered Dec 04 '22 21:12

askrynnikov


I implemented rack-timeout. Setting the correct timeouts corrected my problem. The proper method to set those variables is in a config.ru use statement as follows:

use Rack::Timeout, service_timeout: 5
like image 33
Richard_G Avatar answered Dec 04 '22 21:12

Richard_G