Rails 5 Action Cable握手404错误排查请求:Nginx下Puma/Passenger失效
Hey there, let's dig into troubleshooting your flaky WebSocket communication between Rails and AngularJS behind Nginx. I’ve tackled similar intermittent WebSocket issues before, so here’s a structured approach to get to the bottom of it:
First off, your provided Nginx config doesn’t include any handling for WebSocket upgrade requests—and that’s a critical gap. WebSockets rely on the Upgrade HTTP header to switch from HTTP to the WebSocket protocol, and Nginx won’t do this automatically.
Update your Nginx server block with these WebSocket-specific rules (adjust the /cable path if your Rails Action Cable endpoint uses a different route):
server { listen 80; server_name server_ip; root /home/ubuntu/project_path/public/; rails_env dev; # Enable Passenger (if sticking with it) passenger_enabled on; # Critical WebSocket configuration for Action Cable location /cable { # For Passenger: Disable concurrent request limits to preserve long-lived WebSocket connections passenger_app_group_name your_project_action_cable; passenger_force_max_concurrent_requests_per_process 0; # Proxy headers to handle WebSocket upgrade 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; # If using Passenger, this points to your app; if using Puma, replace with your Puma socket/port proxy_pass http://unix:/path/to/your/app/tmp/sockets/puma.sock; # or http://localhost:3000 for Puma } # Your existing Nginx rules here... }
Assuming you’re using Rails’ built-in Action Cable (standard for Rails 5+), double-check these configs:
config/cable.yml: Ensure your dev environment uses a stable adapter (avoidasyncfor anything beyond local testing—it’s not designed for multi-process setups):dev: adapter: redis url: redis://localhost:6379/1config/routes.rb: Confirm you’ve mounted Action Cable:mount ActionCable.server => '/cable'- AngularJS Connection: Make sure your frontend is connecting to the correct WebSocket URL, e.g.,
ws://server_ip/cable(not an HTTP URL).
Since you’re using Passenger 5.2.1, keep these in mind:
- The
passenger_force_max_concurrent_requests_per_process 0line is non-negotiable—it disables Passenger’s default request concurrency limits that would kill long-lived WebSocket connections. - Check Passenger logs (
/var/log/nginx/passenger.log) for errors related to WebSocket upgrades or connection timeouts.
If you try Puma again, update your config/puma.rb to support long-lived connections:
workers 2 threads 1, 6 bind 'tcp://0.0.0.0:3000' # or use a Unix socket for better performance persistent_timeout 240 # Extend timeout to keep WebSocket connections alive
Then adjust your Nginx proxy_pass to point to Puma’s port/socket instead of Passenger.
The fact that it works in specific networks points to environmental factors:
- Firewalls/Security Groups: Verify your server’s firewall (e.g.,
ufw) allows inbound traffic on port 80. Also, check if client-side networks have firewalls that block WebSocketUpgraderequests (some restrictive proxies/firewalls do this). - Sticky Sessions: If you’re using multiple app servers (Puma workers/Passenger instances), ensure your load balancer (if any) uses sticky sessions—WebSockets require a persistent connection to a single backend process.
- DNS/Routing: In networks where it fails, test if the server IP resolves correctly, and check for routing fluctuations that might drop connections mid-handshake.
Always check logs to pinpoint failures:
- Nginx logs:
/var/log/nginx/access.log(look for 101 status codes for successful WebSocket upgrades, or 404/502 for failures) and/var/log/nginx/error.logfor proxy errors. - Rails logs:
log/development.logto see if Action Cable is receiving connection attempts and any associated errors. - Passenger/Puma logs: Check for connection termination messages or process crashes.
Start with the Nginx WebSocket config—this is the most likely fix for your intermittent issues. Let me know if you hit specific errors while testing these steps!
内容的提问来源于stack exchange,提问作者sjcoder

