Trying to deploy super simple rails 5 application to AWS using beanstalk.
Everything works fine except actioncable. Browser can't connect to the cable server.
WebSocket connection to 'ws://prod.3x52xijcqx.us-west-1.elasticbeanstalk.com/cable' failed: Error during WebSocket handshake: Unexpected response code: 404
I found similar questions at stackoverflow but all of them were pointing to configure nginx using this template, however it didn't help me.
I customized nginx config using this script which I've put inside .ebextensions
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 prod.3x52xijcqx.us-west-1.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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
container_commands:
01_restart_nginx:
command: "service nginx restart"
Full app source is here
Related
Hi
my problem is that I have 502 error when trying to connect to localhost:8090.
Setup is made on running Docker container with Mariadb (MySql) in it.
Ports: 80 and 8080 work great. Database is running (Alpine Linux - Mariadb). Localhost on port 80 and 8080 shows what should show.
I haven't had anything to do with nginx configuration before.
In Error log I have this:
2022/08/04 20:55:53 [emerg] 302#302: open() "/conf/nginx/nginx.conf"
failed (2: No such file or directory)
In conf file:
user root; worker_processes 2; events { worker_connections 1024; }
http { include mime.types; default_type application/octet-stream;
sendfile on; keepalive_timeout 65; include
/etc/nginx/sites-enabled/*; } daemon off;
In sites-enabled: server {
listen 8090;
root /usr/bin;
server_name localhost;
access_log /dev/null;
error_log /dev/null;
location / {
proxy_pass http://127.0.0.0:7001;
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-Fowarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Fowarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
try_files $uri $uri/ =404;
}
location ~ \.(gif) {
root /var/lib;
}
What should I do?
I'm trying to connect to an ActionCable websocket and everything works fine running locally with just Puma and without nginx.
However, when I try to do the exact same thing on my staging environment, the connection is immediately closing after connecting. I am able to get the downstream welcome messages and maybe a ping.
However, the connection abruptly closes without any of the onClose callbacks so my guess is nginx is not letting the connection persist.
Here is my sites nginx configuration.
upstream app {
# Path to Puma SOCK file, as defined previously
server unix:/home/deploy/my-app/shared/tmp/sockets/puma.sock fail_timeout=60;
keepalive 60;
}
server {
listen 80;
server_name localhost;
# websocket_pass websocket;
root /home/deploy/my-app/current/public;
try_files $uri/index.html $uri #app;
location #app {
proxy_pass http://app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}
#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 also found this error in nginx error logs:
2019/02/11 21:08:35 [error] 10233#10233: *2 recv() failed (104: Connection reset by peer) while proxying upgraded connection, client: x.x.x.x, server: localhost, request: "GET /cable/ HTTP/1.1", upstream: "http://unix:/home/deploy/wr-api/shared/tmp/sockets/puma.sock:/cable/", host: "x.x.x.x"
So after some time, we noticed that the staging environment cable.yml had this value for url:
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
Removing that value and all other values except for adapter: staging fixed it for us.
New cable.yml staging config:
staging:
adapter: redis
Working!
I have created a Rails 5.0 app with Elastic Beanstalk on Amazon Web Services and I have been able to successfully create the website with a functioning database. The only problem is that I need ActionCable for my app to work and it is really hard for me to configure Elasticache and have the rails app successfully communicate to the Elasticache cluster.
A lot of people have told me that the load balancer in Elastic Beanstalk doesn't allow any communication to the the Elasticache cluster and I haven't been able to find any documentation on how to integrate Redis into Elastic Beanstalk in order to properly configure ActionCable.
Do you guys knows a step by step detailed approach to successfully set up ActionCable on Elastic Beanstalk Rails 5.0 app using Elasticache?
Most important thing is to change the loadbalancer to user TCP and SSL instead of HTTP and HTTPS. You also need to configure nginx to pass on the upgrade headers on the /cable location.
Try adding this file (nginx.config) in your .ebextensions folder:
files:
/etc/nginx/conf.d/proxy.conf:
content: |
client_max_body_size 500M;
server_names_hash_bucket_size 128;
upstream backend {
server unix:///var/run/puma/my_app.sock;
}
server {
listen 80;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
server_name *.cmgresearch.net;
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;
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;
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
container_commands:
01restart_nginx:
command: "service nginx restart"
See https://blog.cmgresearch.com/2017/05/11/step-7-action-cable-on-elastic-beanstalk.html
I am using websocket-rails gem for handling messaging service for my application.
Tech Stack: Rails 4.2.5, Ruby 2.3.0p0, Passenger as app-server(Also tried with Puma), Thin as websocket server on port 3001, ngnix as web server and
Websocket patch of gem 'websocket-rails', github: 'moaa/websocket-rails', branch: 'sync_fixes'
When an client hits the websocket server, it actively triggers the server event of client_connected and I can see on websocket_rails_server.log the message that I print, i.e.
"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
"+++++++++++ WebsocketRails Client CONNECTED ++++++++++++++"
"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
But, on client end it abruptly ends with response:
WebSocket connection to 'ws://beta.server.com/websocket' failed: Error during WebSocket handshake: Unexpected response code: 504
I have tried with every solution on Github issues as well as Stackoverflow related question, but no help yet.
My nginx config is as follows(if that's needed anyway):
server {
listen 80;
server_name beta.server.com;
root /var/www/server-rails/current/public;
proxy_cache_bypass 1;
proxy_no_cache 1;
location /websocket {
proxy_pass http://localhost:3001/websocket;
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
add_header Access-Control-Allow-Origin *;
proxy_set_header Upgrade websocket;
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;
}
passenger_enabled on;
passenger_sticky_sessions on;
passenger_app_env staging;
}
I'm trying to setup websockets on my rails application. My application works with iOS client that uses SocketRocker library.
As websockets backend i use faye-rails gem.
It is integrated to the rails app as rack middleware
config.middleware.delete Rack::Lock
config.middleware.use FayeRails::Middleware, mount: '/ws', server: 'passenger', engine: {type: Faye::Redis, uri: redis_uri}, :timeout => 25 do
map default: :block
end
It works perfect until i upload it to the production server with Nginx. I have tried a lot of solutions to pass websocket request to the backend, but with no luck. The main thing is there are two servers running, but i have just one. My idea was i just needed to proxify requests from /faye endpoint to /ws (to update headers). What is correct proxy_pass parameters should be in my case?
location /faye {
proxy_pass http://$server_name/ws;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
I had a similar problem and after struggling for a while, I finally could make it work.
I'm using nginx 1.8 with thin server with gem 'faye-rails' and my mount point is /faye
My nginx config looked like this:
upstream thin_server {
server 127.0.0.1:3000;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
...
proxy_redirect off;
proxy_cache off;
location = /faye {
proxy_pass http://thin_server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
}
location / {
try_files $uri/index.html $uri.html $uri #proxy;
}
location #proxy {
proxy_pass http://thin_server;
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;
}
...
}
The final turn point for me to make it work was when I set the "location = /faye". Before I tried "location /faye" and "location ~ /faye" and it failed.
It looks like the equal sign "=" prevents nginx to mix with other location settings.