1

The ElasticBeanstalk is an Application Load Balancer configuration. It's a Ruby on Rails, with Passenger, Puma and NGINX (Default Ruby AWS Stack).

I'm forcing ssl, and I have everything working perfectly, except for the websockets, that seems to be (blocked|discarded|broken).

The first error is displayed in the console: (URL is my domain)

WebSocket connection to 'wss://<URL>/cable' failed: WebSocket is closed before the connection is established.

This request fails with (OPCODE -1) in the frontend.

By checking the server logs, I have access.log that's showing:

/cable"499 which is not a very descripting error.

And the rails production.log shows:

Started GET "/cable/" [WebSocket] for 152.170.14.251 at 2018-05-28 21:01:27 +0000

Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)

Registered connection (Z2lkOi8vYXNlc29yLWFwcC9JZGVudGl0eS81:Z2lkOi8vYXNlc29yLWFwcC9Vc2VyLzI)

WebSocket error occurred: wrong number of arguments (given 2, expected 1)

Sometimes I saw this other error:

NoMethodError: undefined method `+' for nil:NilClass

File "/opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/websocket-driver-0.7.0/lib/websocket/driver/hybi.rb" line 11 in generate_accept
File "/opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/websocket-driver-0.7.0/lib/websocket/driver/hybi.rb" line 76 in initialize
File "/opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/websocket-driver-0.7.0/lib/websocket/driver.rb" line 160 in new
File "/opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/websocket-driver-0.7.0/lib/websocket/driver.rb" line 160 in rack
File "/opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/actioncable-5.2.0/lib/action_cable/connection/client_socket.rb" line 47 in initialize

And that file showed that a key is missing.

By following that error I found this issue:

Rails Issue

That lead me to this final file:

File variable that seems to be missing

That finally lead me to this configurations that might be the ones missing:

socket.env

After a lot of investigation I ended up in the gem source code, and looks like the encoding of some characters is failing and creating a weird string that ActionCable is not able to parse:

Open Issue in Github

Jorge de los Santos
  • 4,583
  • 1
  • 17
  • 35

1 Answers1

0

For the default Ruby AWS stack (you mentioned), you will need to edit the default nginx configuration to support websockets. The default nginx config for the Elastic Beanstalk/Ruby/Puma stack can be found here.

Basically, you will need to add these http headers for websockets:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";

A way to go about doing this is to add an .ebextensions folder in your project's root directory, and place a config file inside with a customized version of the default configuration. Ex:

# .ebextensions/001_nginx.conf

files:
   "/opt/elasticbeanstalk/support/conf/webapp_healthd.conf":
     owner: root
     group: root
     mode: "000644"
     content: |
       upstream my_app {
         server unix:///var/run/puma/my_app.sock;
       }

       log_format healthd '$msec"$uri"'
                       '$status"$request_time"$upstream_response_time"'
                       '$http_x_forwarded_for';

       server {
         listen 80;
         server_name _ localhost; # need to listen to localhost for worker tier

         if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") {
           set $year $1;
           set $month $2;
           set $day $3;
           set $hour $4;
         }

         access_log  /var/log/nginx/access.log  main;
         access_log /var/log/nginx/healthd/application.log.$year-$month-$day-$hour healthd;

         location / {
           proxy_pass http://my_app; # match the name of upstream directive which is defined above
           proxy_set_header Host $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_http_version 1.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "Upgrade";
         }

         location /assets {
           alias /var/app/current/public/assets;
           gzip_static on;
           gzip on;
           expires max;
           add_header Cache-Control public;
         }

         location /public {
           alias /var/app/current/public;
           gzip_static on;
           gzip on;
           expires max;
           add_header Cache-Control public;
         }
       }

container_commands:
  99_restart_nginx:
    command: "service nginx restart || service nginx start"

After deploying this config, If you have SSH setup for your EB instance you can SSH in and check your nginx config to see if your modified version is being used. If you're not seeing changes here or in the logs and this is not a production instance, you might want to consider rebuilding the environment from the AWS console.

Ricky Brown
  • 644
  • 5
  • 8
  • I already found and tryed this script, but it's overwritting the passenger script configuration and creating another listener in the port 80 that is used by the same passenger. And as I stated in the last part of the question, the issue is related with a gem parsing a binary string with wrong encoding. – Jorge de los Santos May 31 '18 at 17:55