Rails 5 actioncable freezes the server - ruby-on-rails

I am having issue running Actioncable on nginx server, every time I mount actioncable
mount ActionCable.server => '/cable'
the server will return
Started GET "/cable" for ::1 at 2016-05-24 11:42:16 -0400
Started GET "/cable/" [WebSocket] for ::1 at 2016-05-24 11:42:16 -0400
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
before freezing
Any help is appreciated!

I was having this same issue once my application was being used by many users. My problem came from using Puma and Phusion Passenger together. This issue was solved by eliminating Puma from my application and configuring Nginx to use Action Cable with Passenger instead.
This article outlines the correct way to configure Action Cable + Nginx + Passenger

I had same problem. Rails server was freezing after connecting
This worked for me
In config.ru file
if defined?(PhusionPassenger)
PhusionPassenger.advertised_concurrency_level = 0
end
Idea is that set concurrency level to 0
Initially i was setting concurrency level 0 for cable server only in nginx.conf file
Hope this save someone's day

If you are using puma + nginx + rails you should use :
Inside your virtual host in nginx conf
# enables WS support
location /cable {
proxy_pass http://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";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
}

Related

.Net core POST API in NGINX reverse proxy throws error 404

This is my first time posting a question. Kindly let me know if I am missing something that needs to be shared.
I am trying to POST some data into database through my C# APP and API (separately build), but it throws error 404 only for the POST API. All other pages work fine and so does the GET request. The app and API have been deployed on a LINUX machine through NGINX reverse proxy server. Both of them work on HTTP protocol. The feature works for localhost, but not for IP dependent URL.
Here is the content of service file for the app, I do not know what is missing in it. Please take care of the "/" as well where ever it is needed. While performing RnD, I found that the POST request in NGINX gets redirected to GET, I don't know if this will be helpful or not, but felt like sharing.
server {
listen myIP:6002;
server_name attendancepp;
root /home/user/net-core/Publish/AttendanceModule/AttendanceApp;
location /AttendanceApp/{
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://myIP:6002/;
proxy_set_header Accept-Encoding "";
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The app works on the URL http://myIP:6002/attendance/allPages . All the pages are accessible without any issue. Just the POST part is not working.
Thank you, in advance.
working fine after commenting
try_files $uri $uri/ =404
cd /etc/nginx/sites-available/
sudo nano default << nginx
edit file then CTR+X and 'y' for yes
sudo systemctl restart nginx

Faye requesting an insecure script <URL>

I'm was exploring faye to implement websocket feature but got stuck due to following issue.
The page at was loaded over HTTPS, but requested an insecure script http://xyz/faye?message=[{"channel":"/meta/handshake","version":"1.0","supportedConnectionTypes":["websocket","eventsource","long-polling","cross-origin-long-polling","callback-polling"],"id":"1"}]&jsonp=__jsonp1. This request has been blocked; the content must be served over HTTPS
Config details
rails( 4.2.11)
faye (1.3.0)
puma (4.3.1)
Everything fine locally since everything running over HTTP.
On staging, we are getting the above issue. Not sure what are we doing wrong. Points to note are:
Puma is running using --ssl.
https://xyz/faye.js renders the client JS (Note the https)
Ran faye server using rackup faye.ru -s thin -E production
nginx config below
server {
listen 80;
root /var/app/current;
location / {
proxy_pass http://mlp;
proxy_set_header Host $host;
rewrite /favicon.ico /public/favicon.ico;
}
location /faye {
proxy_set_header Host $host;
proxy_pass http://localhost:9292;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
}
}

Rails5 Action Cable Nginx 404 and 502 errors

Everyone :).
I know people have already faced alot of problems related to mine. I have tried all but my issue has not been resolved. I have been working from past 3 days to fix this but I am unable to do it.
I am using ActionCable for the first time and on development server it is working fine. But in production where I am using Puma and Nginx I am facing terrible issues.
Initially when I had not (location /cable) settings in nginx configuration, server gives me 404 handshake error
i.e Error during WebSocket handshake: Unexpected response code: 404
Then after I add following location /cable configuration in nginx configuration I start getting 502 bad gateway error.
Note: I have not opened any port specifically for ActionCable. I assume it is not required. only port 80 is open on my server.
I need some expert to help me with this. I need quick help to get it fixed. Thanks in advance :)
I have these two lines present in my environment/production.rb
config.action_cable.url = "ws://my_linode_domain/cable"
config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/]
This is my nginx config file
upstream app {
# Path to Puma SOCK file, as defined previously
server unix:/home/deploy/artcrate/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
#server_name localhost;
server_name my_linode_domain
# prevents 502 bad gateway error
large_client_header_buffers 8 32k;
root /home/deploy/artcrate/current/public;
try_files $uri/index.html $uri #app;
location / {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_pass http://app;
}
location ~ ^/(assets|fonts|system)/|favicon.ico|robots.txt {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location /cable{
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
I have tried various proxy_pass options in location /cable settings but none worked.
Everyone. :)
After a week of struggle, hardwork and constantly playing around with nginx and puma configuration files and keenly reading blogs again and again, I was able to figure out the issue.
My nginx configurations were correct. I had to add two more lines to puma.rb configuration which don't come with default configurations. Those two lines are:
workers 2
daemonize true
daemonize true: this tells puma to run in the background by spawning a subprocess and detaching it from the executing shell. If you don't use daemonize, you need to run the puma process via nohup and put it in the background explicitly.
I am not sure if I required workers 2 but I had added them while resolving my issue. So I let it there. But after adding above two lines my ActionCable started to work normally.
RAILS and RUBY version I am using for this project is
Rails 5.0.7
ruby 2.3.1p112
ok. So today I wanted to integrate Action Cable again in my project but faced the same issue again. I applied my above solution but it didn't work. Last time although it worked but I wasn't satisfied with the solution thinking that why would ActionCable work in single thread/worker on local machine.
But this time I focussed and figured out the culprit.
Culprit is NGINX configuration
Configuration when I was facing 404 handshake errors
location /cable {
proxy_pass http://example.com;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection Upgrade;
}
Configuration when all started working fine.
location /cable {
proxy_pass http://puma;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection Upgrade;
}
so the culprit line was:
proxy_pass http://example.com;
Here we are pointing it to NGINX which is wrong, it should point to our puma server path which in my configuration is represented by 'puma'.
Here is the Summary of my implementation of ActionCable and its working copy on Production Server
So to integrate Action Cable with Rails 5 you need to follow following steps:
Setup Redis on default port.
Add these lines in environments/staging.rb or environments/production.rb, depending on your application environment.
config.action_cable.url = [/ws://*/, /wss://*/]
config.action_cable.allowed_request_origins = [/http://*/, /https://*/]
Finally setup you NGINX file as explained above. Here is my complete NGINX configuration in gist nginx.conf. I had replaced my site name with 'example.com' and project name with 'example'. So if you are copying anything, just make sure you replace those with yours otherwise nothing will work as paths will be broken.
I hope this will really release the pain while pushing ActionCable to live application and resolve this handshake error for anyone as this is very very tricky and technical thing and a lot of docs just mention to point action cable to your main site url and not puma server running behind your nginx.
Thanks.

Websocket-rails doesn't work on production evironment with Nginx and Unicorn

I have Rails 3.2 application with gem websocket-rails 0.7.
On development machine, all work fine
On production enviroment, I use Nginx/1.6 as proxy server and Unicorn as http server. Thin is used on standalone mode (following https://github.com/websocket-rails/websocket-rails/wiki/Standalone-Server-Mode).
nginx config:
location /websocket {
proxy_pass http://localhost:3001/websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
On backend side, I have the following code for send notification to clients
WebsocketRails[:callback_requests].trigger 'new', call_request
On client side, I got a connection using:
dispatcher = new WebSocketRails window.location.host + ':3001/websocket'
channel = dispatcher.subscribe 'callback_requests'
But notification doesn't come to the client.
Related issue on github - github.com/websocket-rails/websocket-rails/issues/211
Your nginx config is matching requests below /websocket/ with the trailing /. That is the directory component of /websocket/blah.
If you look in your nginx access log file you'll find your requests to /websocket are being 301 redirected to /websocket/.
Remove the trailing /
location /websocket {
proxy_pass http://localhost:3001/websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

Can one application with one server serve websockets and http traffic?

Is this somehow possible? Is it possible to do something like this in Ruby on top of Rack? I've seen there's websockets-rack but as far as I understand, that is only a rack module to serve ONLY websocket traffic not http also.
So basically, as the question states, is it possible to serve both protocols with just one server on the same port, instead of firing of something like Faye, websockets-rack or em-websockets?
Websockets are just an in-protocol upgrade of HTTP(s), so they are not normal TCP sockets but reuse the existing HTTP(S) connection (and thus use the same port). So, in theory it should work and from what I know it works with the Perl Mojolicious framework. But I don't know if it works work ruby/rack.
The short answer is - (AFAIK) no.
Currently, a ruby HTTP server (like rails or sinatra) and a websocket server are mutually exclusive.
After saying that, you could use a third party to emulate that. Specifically Ngnix. With Nginx you can listen to a single port, but, accroding to a path, decide whether you want to dispatch the request to the HTTP server or the Websocket server.
For example, you can run the HTTP server on port 3000, and the Websocket server on port 3020, and then configure the nginx.conf like this:
upstream http_app {
server 127.0.0.1:3000;
}
upstream websocket_app {
server 127.0.0.1:3020;
}
server {
listen 80;
server_name .example.com;
access_log /var/www/myapp.example.com/log/access.log;
error_log /var/www/myapp.example.com/log/error.log;
root /var/www/myapp.example.com;
index index.html;
location /web {
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;
proxy_redirect off;
proxy_pass http://http_app;
}
location /socket {
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;
proxy_redirect off;
proxy_pass http://websocket_app;
}
}
Now any request to http://www.example.com/web/... will reach the HTTP server, and any request to http://www.example.com/socket will reach the Websocket server.

Resources