Nginx, Faye, Private...trying to figure out configuration - ruby-on-rails

Using Nginx 1.6 with private_pub gem
Here are my config files:
private_pub.ru
# Run with: rackup private_pub.ru -s thin -E production
require "bundler/setup"
require "yaml"
require "faye"
require "private_pub"
Faye::WebSocket.load_adapter('thin')
PrivatePub.load_config(File.expand_path("../config/private_pub.yml", __FILE__), ENV["RAILS_ENV"] || "development")
run PrivatePub.faye_app
Private_pub.yml
development:
server: "http://localhost:9292/faye/faye"
secret_token: "secret"
test:
server: "http://localhost:9292/faye/faye"
secret_token: "secret"
production:
server: "http://xxxxx.com/faye/faye"
secret_token: "my secret token"
signature_expiration: 3600 # one hour
in my Nginx.conf
location /faye {
proxy_pass http://0.0.0.0:9292;
break;
}
The service is running but really really slow and I get those errors on safari:
WebSocket connection to 'ws://xxxxx.com/faye' failed: Unexpected response code: 400
Failed to load resource: the server responded with a status of 404 (Not Found)
Failed to load resource: the server responded with a status of 502 (Bad Gateway)
Any thoughts?

OK.. I found the solution for those who ever want to install Faye/Private_pub on Nginx running thin and unicorn.
First:
You have to understand that your upstream server is your localhost:9292 (127.0.0.1:9292)
you set your upstream in your Nginx conf by adding the following:
location /faye {
proxy_pass http://127.0.0.1:9292;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_redirect off;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_set_header X-Forwarded-Proto https;
break;
}
Also for those who have a 504 after that change the config file in the Nginx and php.fmp (if you have it) so that the timeout is increased.
Don't forget to reload your Nginx. If you still have errors check your Nginx error.log

Related

Rails 6 ActionCable Unable to Upgrade WebSocket Request

I have been struggling to get my Rails app deployed correctly for a while now, and have decided it is finally time to consult the community for some help. I have read just about every stackoverflow post on this issues, including the following, with no luck:
Rails 5 ActionCable fails to upgrade to WebSocket on Elastic Beanstalk -> From this post I ensured I was using an Application Load Balancer
ActionCable on AWS: Error during WebSocket handshake: Unexpected response code: 404 -> Configured an nginx proxy, with no change
Problem Description
I am using the following setup:
Ruby 2.7.5
Rails 6.1.0
GraphQL
React Frontend (separate repo)
Elastic Beanstalk
Ruby 2.7 running on 64bit Amazon Linux 2/3.4.1
Application Load Balancer
Postgres ActionCable adapter
My application is deployed to AWS Elasticbeanstalk and all requests to /graphql are successful. However, when attempting to connect to /cable I get this error in my browser console:
WebSocket connection to 'wss://api.redacted.io/cable' failed:
When checking the Elastic Beanstalk logs I see:
/var/app/containerfiles/logs/production.log:
I, [2022-02-20T19:35:25.849990 #32761] INFO -- : [8e1d3e86-81cc-4708-89d3-ebad56470f8f] Started GET "/cable" for <redacted IP> at 2022-02-20 19:35:25 +0000
I, [2022-02-20T19:35:25.850342 #32761] INFO -- : [8e1d3e86-81cc-4708-89d3-ebad56470f8f] Started GET "/cable/"[non-WebSocket] for <redacted IP> at 2022-02-20 19:35:25 +0000
E, [2022-02-20T19:35:25.850384 #32761] ERROR -- : [8e1d3e86-81cc-4708-89d3-ebad56470f8f] Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: close, HTTP_UPGRADE: )
I, [2022-02-20T19:35:25.850419 #32761] INFO -- : [8e1d3e86-81cc-4708-89d3-ebad56470f8f] Finished "/cable/"[non-WebSocket] for <redacted IP> at 2022-02-20 19:35:25 +0000
Potentially Relevant Files
cable.yml:
development:
adapter: postgresql
test:
adapter: test
production:
adapter: postgresql
production.rb:
...
config.action_cable.url = 'wss://api.redacted.io/cable'
config.action_cable.allowed_request_origins = ['redacted.io', 'http://redacted.io', 'https://redacted.io']
...
.ebextensions/nginx_proxy.config:
files:
"/etc/nginx/conf.d/websockets.conf" :
content: |
upstream backend {
server unix:///var/run/puma/my_app.sock;
}
server_names_hash_bucket_size 128;
server {
listen 80;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
server_name redacted.elasticbeanstalk.com;
# prevents 502 bad gateway error
large_client_header_buffers 8 32k;
location / {
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_set_header X-NginX-Proxy true;
# prevents 502 bad gateway error
proxy_buffers 8 32k;
proxy_buffer_size 64k;
proxy_pass http://backend;
proxy_redirect off;
location /assets {
root /var/app/current/public;
}
# enables WS support
location /cable {
proxy_pass http://backend/cable;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
container_commands:
01restart_nginx:
command: "nginx -t && service nginx restart"
After posting on reddit, I was able to fix my issue by:
Removing my .ebextensions/nginx_proxy.config file.
Creating a new file, .platform/nginx/conf.d/elasticbeanstalk/websocket.conf with the contents:
location /cable {
proxy_pass http://my_app/cable;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Could not connect websocket using Action Cable

Could not connect websocket using Action Cable in Rails 5.1. HTTP server is Unicorn on nginx and adapter is Redis.
Rails configuration is the following.
# config/environments/production.rb
config.action_cable.disable_request_forgery_protection = true
nginx configuration is the following.
upstream unicorn {
server unix:/rails/current/tmp/sockets/unicorn.sock;
}
server {
listen 80;
charset utf-8;
server_name sub.example.com;
root /rails/current/public;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://unicorn;
break;
}
}
location /cable {
proxy_pass http://unicorn;
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 X-Forwarded-Proto https;
proxy_redirect off;
}
...
}
Errors in console of web browser are the following.
WebSocket connection to 'wss://sub.example.com/cable' failed: Error during WebSocket handshake: Unexpected response code: 404
Errors in Rails are the following.
[ERROR] Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: close, HTTP_UPGRADE: )
[INFO] Finished "/cable/"[non-WebSocket] for xxx.xxx.xxx.xxx at 2017-xx-xx
A strangest thing is a error in Rails does not have HTTP_UPGRADE value. But HTTP request headers of web browser include Upgrade key and websocket value. Also setting "websocket" for proxy header in nginx configurations.
What should I do?
On the back of that writeup, I just realized the universal solution is
a simple change to the config/secrets.yml file to reference the
ENV["PORT"] setting
...
# Be sure to restart your server when you modify this file.
development:
secret_key_base: 231bf79489c63f8c8facd7...
action_cable_url : http://localhost:<%= ENV["PORT"] %>
test:
secret_key_base: 1ab8adbcf8410aebb...
action_cable_url : http://localhost:<%= ENV["PORT"] %>
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
action_cable_url : <%= ENV["SERVER_PORT"] %>
.
You can also have this in your dot file:
export PORT=3000
source

Websocket connection failed with nginx and faye

I'm trying to introduce chatting to my Rails app. For this purpose I used gem private_pub and it works perfectly in development mode.
In production I was using Apache + Passenger, but I couldn't configure Faye with it, so I changed Apache to Nginx. My main app is still on Apache server, and this demo on Nginx with port 8080 (just for test).
I'm able to connect to faye.js by entering http://chat.mysite.com:8080/faye.js, but the connection from app throws an error (browser console).
WebSocket connection to 'ws://localhost:9292/faye' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
After this error, another error appears every 5 seconds.
faye.js:2 GET http://localhost:9292/faye?message=%5B%7B%22channel%22%3A%22%2Fmeta%2Fhands…22%2C%22callback-polling%22%5D%2C%22id%22%3A%221%22%7D%5D&jsonp=jsonp2 net::ERR_CONNECTION_REFUSED
My private_pub.yml
production:
server: "http://localhost:9292/faye"
secret_token: "mysecret"
signature_expiration: 3600 # one hour
My private_pub.ru
require "bundler/setup"
require "yaml"
require "faye"
require "private_pub"
Faye::WebSocket.load_adapter('thin')
PrivatePub.load_config(File.expand_path("../config/private_pub.yml", __FILE__), ENV["RAILS_ENV"] || "development")
run PrivatePub.faye_app
My nginx site.conf
server {
listen 8080;
server_name www.chat.mysite.com;
passenger_enabled on;
passenger_app_env production;
root /var/www/mysite/public;
location ^~ /faye {
proxy_pass http://127.0.0.1:9292;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_buffering off;
proxy_redirect off;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
#proxy_set_header X-Forwarded-Proto https;
proxy_cache_bypass $http_pragma $http_authorization;
proxy_no_cache $http_pragma $http_authorization;
break;
}
}
If I change private_pub.yml to http://localhost:9292/faye/faye, I saw error like "can't load resource /faye/faye.js".
How should I change my Nginx conf or app yml to resolve websocket error?
I see private_pub is quite similar to ActionCable in its design. Before you go too far down the road, you may want read my blog post on "ActionAcable - The good and bad parts" as it addresses suitable use cases when a system like private_pub is good, and when it's not.
If of course you are aware of the shortcomings already, then good luck!
I tried to configure my private_pub.yml as #niceman said. Now all is working good.
production:
server: "http://my-ip:8080/faye"

error installing private pub on live server in rails 4

I am using private pub for one of my projects. Its working fine on localhost but when I deploy it on live server it giving following error:
Errno::ECONNREFUSED in CommentsController#new
Connection refused - connect(2) for "202.164.34.20" port 9292
Here is my private_pub.yml file content for local server:
development:
server: "http://localhost:9292/faye/faye"
secret_token: "secret"
test:
server: "http://localhost:9292/faye/faye"
secret_token: "secret"
production:
server: "http://example.com/faye/faye"
secret_token: "0378a6008f37cbd9c3390ce4069bb85f776d068f7b4885d6890f07066affde25"
signature_expiration: 3600 # one hour
and for other server, here is the file content:
development:
server: "http://202.164.34.20:9292/faye/faye"
secret_token: "secret"
test:
server: "http://202.164.34.20:9292/faye/faye"
secret_token: "secret"
production:
server: "http://localhost:9292/faye/faye"
secret_token: "0378a6008f37cbd9c3390ce4069bb85f776d068f7b4885d6890f07066affde25"
signature_expiration: 3600 # one hour
Now I need to deploy this on http://202.164.34.20:3001 url. please suggest.
localhost:9292 means it will bind to 127.0.0.0, if you want to access from public ip make sure to bind to your external ip or to 0.0.0.0.
Although I would suggest to proxy it with nginx/apache so users can just connect to port 80
Example for nginx
server {
listen 80;
server_name faye.yourdomain.com;
access_log /var/log/nginx/faye.log;
location /faye {
proxy_pass http://127.0.0.1:9292;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_redirect off;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
}
}
map $http_upgrade $connection_upgrade {
default Upgrade;
'' close;
}

Nginx errors with Rails+Faye+Puma on Dokku Digital Ocean

Good day!
I want to run websocket app with Faye gem, but the following problem occurs: when I deploy my app on production server, Ngix can't receive faye.js and can't connect to faye server. In Nginx error.log I found next errors:
2014/12/24 15:44:39 [error] upstream prematurely closed connection while reading response header from upstream, client: 46.0.121.23, server: example.com, request: "GET /faye HTTP/1.1", upstream: "http://127.0.0.1:9292/faye", host: "example.com"
2014/12/24 15:44:39 [error] *1 connect() failed (111: Connection refused) while connecting to upstream, client: 46.0.121.23, server: example.com, request: "GET /faye HTTP/1.1", upstream: "http://127.0.0.1:9292/faye", host: "example.com"
I try the How to start faye server on a rails app deployed using dokku? and Error 502 Bad Gateway on NGINX + rails + dokku answers, but it's not help for me.
My Procfile is
web: bundle exec rails s Puma -p 5000
faye: bundle exec rackup s Puma faye.ru
My faye.ru is
require 'faye'
require File.expand_path('../config/initializers/faye_token.rb', __FILE__)
class ServerAuth
def incoming(message, callback)
if message['channel'] !~ %r{^/meta/}
if message['ext']['auth_token'] != FAYE_TOKEN
message['error'] = 'Invalid authentication token.'
end
end
callback.call(message)
end
end
faye_server = Faye::RackAdapter.new(:mount => '/faye', :timeout => 0)
faye_server.add_extension(ServerAuth.new)
run faye_server
My nginx.conf is:
upstream example.com { server 127.0.0.1:49169; }
server {
listen [::]:80;
listen 80;
server_name example.com;
location / {
proxy_pass http://example.com;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Request-Start $msec;
}
location /faye {
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_buffering off;
proxy_cache_bypass $http_pragma $http_authorization;
proxy_no_cache $http_pragma $http_authorization;
proxy_pass http://localhost:9292;
}
}
My app get faye.js next:
<%= javascript_include_tag "http://example.com/faye.js" %>
And connect to faye server
$(function() {
var faye = new Faye.Client('http://example.com/faye');
faye.subscribe('/comments/new', function (data) {
eval(data);
});
});
What can I do? In development enviroment all works fine, but in production only errors.
Try to config from this gist
https://gist.github.com/Bubelbub/0a942a0d51a3d329897d
In server section:
large_client_header_buffers 8 32k;
In faye location:
proxy_buffers 8 32k;
proxy_buffer_size 64k;

Resources