添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
礼貌的风衣  ·  LSTM&GRU - bubbleeee ...·  1 年前    · 
至今单身的风衣  ·  CentOS 6.x ...·  1 年前    · 
完美的红薯  ·  Django基础(39): ...·  1 年前    · 
帅呆的四季豆  ·  解决json.dumps ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

ActionCable doesn't work in production. Works well in development, but not in production.

Running Nginx with Puma on Ubuntu 14.04. I have checked that redis-server is up and running.

Rails -v 5.0.0.1

production.log :

INFO -- : Started GET "/cable/"[non-WebSocket] for 178.213.184.193 at 2016-11-25 14:55:39 +0100
ERROR -- : Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: close, HTTP_UPGRADE: )
INFO -- : Finished "/cable/"[non-WebSocket] for 178.213.184.193 at 2016-11-25 14:55:39 +0100

Request from client:

GET ws://mityakoval.com/cable HTTP/1.1
Host: mityakoval.com
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://mityakoval.com
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4,uk;q=0.2,nb;q=0.2
Cookie: _vaktdagboka_session=******
Sec-WebSocket-Key: *******
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Protocol: actioncable-v1-json, actioncable-unsupported

Response:

HTTP/1.1 404 Not Found
Server: nginx/1.4.6 (Ubuntu)
Date: Fri, 25 Nov 2016 13:52:21 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-cache
X-Request-Id: d6374238-69ef-476e-8fc5-e2f8bbb663de
X-Runtime: 0.002500

nginx.conf:

upstream puma {
  server unix:///home/mityakoval/apps/vaktdagboka/shared/tmp/sockets/vaktdagboka-puma.sock;
server {
  listen 80 default_server deferred;
  # server_name example.com;
  root /home/mityakoval/apps/vaktdagboka/current/public;
  access_log /home/mityakoval/apps/vaktdagboka/current/log/nginx.access.log;
  error_log /home/mityakoval/apps/vaktdagboka/current/log/nginx.error.log info;
  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  try_files $uri/index.html $uri @puma;
  location @puma {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://puma;
  location /cable {
    proxy_pass http://puma;
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
  error_page 500 502 503 504 /500.html;
  client_max_body_size 10M;
  keepalive_timeout 10;

cable.yml:

redis: &redis
  adapter: redis
  url: redis://127.0.0.1:6379
production: *redis
development:
  adapter: async
test:
  adapter: async

in production.rb:

config.action_cable.allowed_request_origins = ["http://mityakoval.com"]

in routes.rb:

mount ActionCable.server, at: '/cable'

UPDATE:

Don't forget to restart nginx :) That was the problem for me.

Just a heads up to others: If your nginx is setup as a multi-site server, your configuration file will probably be /etc/nginx/sites-enabled/sitename instead of /etc/nginx/sites-available/default – Dave Collins Jan 3, 2018 at 13:50

You should change the value of proxy_pass property from http://puma to http://puma/cable.

Therefore, the correct location section for the /cable will be:

location /cable {
  proxy_pass http://puma/cable;
  proxy_http_version 1.1;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "Upgrade";

While other posts have correctly posted solutions I thought I'd post a bit more info on how to identify where the problem is/where to fix it for other nginx noobs.

You will know your nginx config needs the proxy_set_header Upgrade at the path you're mounting action cable if the rails error contains HTTP_UPGRADE:. (Meaning nothing is passed to HTTP_UPGRADE). After fixing the problem my logs are showing HTTP_UPGRADE: websocket

  • Gotchya 1: As mentioned by the op, make sure you restart nginx after making a change(I was incorrectly doing this).

  • Gotchya 2: Also look for include statements in the nginx config as your config could be split across multiple files. The location /cable { section should be inside of server { which in my case was missing because it was in a different config file from an includes statement which I didn't notice for a while.

  • Similar error but different problem: Your rails logs will contain an additional error in the logs right before the one the OP mentioned saying the origin is not allowed, that is when your rails config needs to be updated as another answer mentions updating config.action_cable.allowed_request_origins.

  • The logging is subject to change with rails but hopefully this helps clarify where the problem and a few gotchya's I encountered as someone who knows nothing about nginx.

    Thanks in my case there was many server { block, I have placed it one which is listing at port 443 and it start working. – Shoaib May 27, 2021 at 18:20

    Super late to this conversation, however, for anyone who is facing the same error message using Rails5, Action Cable, etc. & DEVISE you simply solve it like suggested here. It all comes down to the web socket server not having a session, hence the error message.

    app/channels/application_cable/connection.rb

    module ApplicationCable
      class Connection < ActionCable::Connection::Base
        identified_by :current_user
        def connect
          self.current_user = find_verified_user
          logger.add_tags 'ActionCable', current_user.name
        protected
          def find_verified_user
            verified_user = User.find_by(id: cookies.signed['user.id'])
            if verified_user && cookies.signed['user.expires_at'] > Time.now
              verified_user
              reject_unauthorized_connection
    

    app/config/initializers/warden_hooks.rb

    Warden::Manager.after_set_user do |user,auth,opts|
      scope = opts[:scope]
      auth.cookies.signed["#{scope}.id"] = user.id
      auth.cookies.signed["#{scope}.expires_at"] = 30.minutes.from_now
    Warden::Manager.before_logout do |user, auth, opts|
      scope = opts[:scope]
      auth.cookies.signed["#{scope}.id"] = nil
      auth.cookies.signed["#{scope}.expires_at"] = nil
    

    Solution was developed by Greg Molnar

    @Micah, i am facing a similar issue on safari, did you manage to find more information about it? – opensource-developer Jul 29, 2020 at 19:33

    The resolution that needs a NGINX configuration changes to accept this action cable request.

    location / {
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    

    Add the above lines to your location block in the nginx site configuration, then restart nginx.

    My solution was to add these lines to my production.rb file:

      config.action_cable.url = 'ws://your_site.com/your_action_cable'
      config.action_cable.allowed_request_origins = [ 'http://your_site.com' ]
    

    Then you should have this key set up in the environment, should look something like this:

    REDIS_URL: 'redis://redistogo:keyblahblahblhblah'
    

    Also, you should have this in production.rb:

    config.web_socket_server_url = "wss://YOUR_URL.com/cable"
                    Ah, okay, I got it. I don't use RedisToGo. Redis server is running on my production server. And I guess it should be ws://... instead of wss://... since I'm not using SSL.
    – mityakoval
                    Nov 26, 2016 at 13:48
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.