如何在生产中使用 Nginx 和 Unicorn 配置 ActionCable?
Posted
技术标签:
【中文标题】如何在生产中使用 Nginx 和 Unicorn 配置 ActionCable?【英文标题】:How to configure ActionCable with Nginx and Unicorn in production? 【发布时间】:2016-07-15 12:57:35 【问题描述】:我最近将我的 Rails 项目从 Rails4 切换到 5.0.0.beta3 以使用很棒的 ActionCable。
我的 ActionCable 服务器在 unicorn 中运行。在开发中一切正常。在生产中我有
Started GET "/cable" for xxx.xxx.xxx.xxx at 2016-03-28 18:06:38 +0300
Started GET "/cable/" [WebSocket] for xxx.xxx.xxx.xxx at 2016-03-28 18:06
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
Registered connection (189772ff-6229-48f1-ae7f-d9a96ad3a6c3)
Finished "/cable/" [WebSocket] for xxx.xxx.xxx.xxx at 2016-03-28 18:06:35
并且这条消息在循环中一次又一次地重复。
我在 *** 上尝试了很多选项来处理这个问题,但没有任何帮助。 我的 nginx 配置:
upstream unicorn
server unix:/tmp/unicorn.my_app.sock fail_timeout=0;
server
server_name www.my_app.com;
return 301 $scheme://my_app.com$request_uri;
server
listen 80 default deferred;
server_name my_app.com;
root /var/www/my_app/current/public;
location ^~ /assets/
gzip_static on;
expires max;
add_header Cache-Control public;
try_files $uri/index.html $uri @unicorn;
location @unicorn
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
location /cable
proxy_pass http://unicorn/cable;
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;
error_page 500 502 503 504 /500.html;
keepalive_timeout 5;
为了确保允许请求,我在初始化程序中临时使用了此代码:
ActionCable.server.config.disable_request_forgery_protection = true
我的cable.coffee
文件
@App ||=
App.cable = ActionCable.createConsumer "/cable"
我的config/cable.yml
文件
production:
adapter: redis
url: redis://localhost:6379/1
我在这个问题上没有太多经验,所以任何帮助都会很棒。
【问题讨论】:
你的路线中有mount ActionCable.server => '/cable'
吗?
@yzalavin 你能解决这个问题吗?我遇到了同样的问题。
@R_G 我也有同样的问题。你能找到问题吗?从我调试的情况来看,unicorn 无法向客户端发送 ping,因此客户端正在尝试重新连接。所以循环中的连接语句。不知道为什么另一个方向的流不起作用
@sethi 请在下面查看我的回复。希望对您有所帮助。
@yzalavin,您找到解决方案了吗?我为它加了赏金。
【参考方案1】:
在location /cable
部分需要添加一行proxy_set_header Host $http_host;
应该是:
location /cable
proxy_pass http://unicorn/cable;
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;
proxy_set_header Host $http_host;
【讨论】:
【参考方案2】:这是我用于我的网站的配置,它似乎工作正常(Rails 5 + Nginx + Unicorn + Capistrano)。您在 sn-p 中看到的包含来自 h5bp/server-configs-nginx,但我认为它们不会成为您的配置不起作用的原因。
upstream example_app
server unix:/home/username/www/example.com/current/tmp/sockets/unicorn.example.com.sock fail_timeout=0;
server
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
server
listen 443 ssl;
server_name www.example.com;
include h5bp/directive-only/ssl.conf;
ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
return 301 https://example.com$request_uri;
server
listen 443 ssl;
server_name example.com;
include h5bp/directive-only/ssl.conf;
ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
root /home/username/www/example.com/current/public;
# Set maximum request body size for uploads
client_max_body_size 25m;
try_files $uri/index.html $uri @unicorn;
location @unicorn
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
proxy_pass http://example_app;
location /cable
proxy_pass http://example_app;
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 Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
access_log /var/log/nginx/example.com/access.log;
error_log /var/log/nginx/example.com/error.log;
charset utf-8;
server_tokens off;
error_page 404 /404.html;
include h5bp/basic.conf;
cable.yml
production:
adapter: redis
url: redis://localhost:6379/1
cable.js
//= require action_cable
//= require_self
//= require_tree ./channels
(function()
this.App || (this.App = );
App.cable = ActionCable.createConsumer();
).call(this);
【讨论】:
【参考方案3】:我实现了rack-timeout。设置正确的超时纠正了我的问题。设置这些变量的正确方法是在 config.ru 使用语句中,如下所示:
use Rack::Timeout, service_timeout: 5
【讨论】:
以上是关于如何在生产中使用 Nginx 和 Unicorn 配置 ActionCable?的主要内容,如果未能解决你的问题,请参考以下文章
nginx + Unicorn + rails 的 IP 地址错误
Unicorn 和 nginx (13: Permission denied)
Rails + (Phusion Passenger|Puma|Unicorn|Thin) + (Nginx|Apache) 如何协同工作?