ActionCable - Failed to upgrade to WebSocket in production ActionCable - Failed to upgrade to WebSocket in production nginx nginx

ActionCable - Failed to upgrade to WebSocket in production


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.


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    end    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        else          reject_unauthorized_connection        end      end  endend

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_nowendWarden::Manager.before_logout do |user, auth, opts|  scope = opts[:scope]  auth.cookies.signed["#{scope}.id"] = nil  auth.cookies.signed["#{scope}.expires_at"] = nilend

Solution was developed by Greg Molnar