带有nginx的Django频道没有客户端收到的消息

时间:2016-09-23 17:13:20

标签: nginx websocket django-channels

我们有一个使用渠道包的应用程序,在localhost上工作得很好。一旦我们点击暂存并在Django前面放置一个nginx框(使用SSL),我们就可以连接到套接字,但客户端不会收到任何消息。

Nginx conf:

worker_processes auto;

error_log /dev/stdout info;

user nobody nogroup;
pid /tmp/nginx.pid;

events {
    worker_connections 1024;
    accept_mutex off;
}

http {
    include mime.types;
    default_type application/octet-stream;
    access_log /dev/stdout;
    sendfile on;
    keepalive_timeout 65;
    gzip on;
    gzip_disable "MSIE [1-6].(?!.*SV1)";
    gzip_vary on;

    upstream ws_server {
        server unix:/tmp/daphne.sock fail_timeout=0;
    }

    server {
        #   redirect all http requests to https
        listen 80;
        listen [::]:80 ipv6only=on;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;

        client_max_body_size 4G;
        server_name changemyip.com;
        keepalive_timeout 5;
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets on;

        ssl_dhparam /etc/nginx/ssl/dhparam.pem;

        location /ws/ {
            try_files $uri @proxy_to_ws;
        }

        location @proxy_to_ws {
            proxy_pass   http://ws_server;

            proxy_redirect      off;
            proxy_set_header    Host              $host;
            proxy_set_header    X-Real-IP         $remote_addr;
            proxy_set_header    X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header    X-Forwarded-Proto $scheme;

            #   Websocket specific
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $http_host;
            proxy_connect_timeout 86400;
            proxy_read_timeout 86400;
            proxy_send_timeout 86400;
        }

        ...
        ssl_protocols TLSv1.1 TLSv1.2;
        ...
        ssl_prefer_server_ciphers on;

        ssl_stapling on;
        ssl_stapling_verify on;
    }
}

Django用gunicorn和websockets运行我加了一个daphne服务器。我可以在daphne日志中看到我的客户端正在连接,但仍然没有收到从daphne到客户端的消息。

Daphne正在创建一个unix套接字,nginx选择进行通信: daphne main.asgi:channel_layer -u /tmp/daphne.sock

2 个答案:

答案 0 :(得分:8)

我遇到了完全相同的问题。我无法通过unix-socket连接,但我找到了一种使用系统端口实现请求管理的简单方法。我使用了以下教程,(并使用了我对Gunicorn的经验),并设法修改了一下他们的Nginx配置文件,我建议你查看教程:

我的Nginx文件

DEBUG==False

我的项目中的websockets运行得非常好(组和频道),所有请求都由Daphne提供,但如果你真的需要使用套接字,这个配置实际上可能对你有帮助。

要考虑的要点

  • 请记住,这个Nginx文件允许Daphne通常连接,但在生产服务器中,您需要运行" Daphne Instance Server"和达芙妮工人"单独能够通过您的频道传输消息。

  • 检查在为频道和群组提供服务时是否使用Redis-Server或其他队列管理器。我这样说是因为我注意到使用" InMemory"配置,丢失了多条消息。

  • 还要检查您的生产环境是否正在将Redis-Server作为守护程序运行。我注意到在几个系统中,Redis-Server甚至无法正常工作,但是当连接被拒绝时,Django应用程序没有引发异常。

  • 你需要一些东西来保持达芙妮和它的工人,因为即使他们循环,他们也不是"异常抗拒"因此,当提出异常时它们会死亡。显然,我建议使用Supervisor或使用Linux系统进行服务。

  • 我不知道达芙妮的工作人员在DJANGO_APP_1时是否可以提供静态和媒体文件,但显然使用Nginx配置分别提供服务更好。

  • 与使用套接字相比,我仍然不知道使用端口的安全/性能影响,所以这是值得检查的(请参阅下文,我发现Daphne或我的配置可能存在错误)

我知道现在这可能与你无关,(我的意思是差不多1个月),但也许有人会对这个答案有所帮助。

未知且非常奇怪的安全问题

TL; DR :不要使用此配置在同一台服务器中删除两个Django-Daphne应用,否则您将度过难关。

通过使用这种配置,我可以在没有任何问题的情况下将Phoenix应用程序与Django应用程序一起部署,但是在使用这种类型的配置部署2个或更多Django应用程序时遇到了问题。出于某种原因,达芙妮知道它必须不断阅读哪些端口来接收请求,但它只是读取所有这些端口并将它们提供给任何它喜欢的人。例如,如果我在同一服务器中运行DJANGO_APP_2DJANGO_APP_2(具有不同的Nginx配置和明显不同的系统端口),有时DJANGO_APP_1的Daphne Workers将窃取请求适用于this.props.route.data和反之亦然。我还没有找到问题的根源,但我认为这与达芙妮的工作人员在一定程度上与他们所涉及的项目无关。 (只是一个理论,我没有时间检查他们的代码)。

答案 1 :(得分:3)

我正在使用daphne gunicorn和nginx,我很难找到nginx的正确配置,在摆弄它之后这个配置对我有用。

​worker_processes  2;

events {
worker_connections  1024;
}

http {

  include       mime.types;
  default_type  application/octet-stream;
  sendfile        on;
  keepalive_timeout  5;

  upstream webserver {
  server 127.0.0.1:8000;
  }

  upstream wsserver {
  server 127.0.0.1:9000;
  }

  server {
    listen 8046;

    client_max_body_size 20M;
    server_name localhost;
    tcp_nodelay     on;

    location / {
        proxy_pass http://webserver;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
   }

   location /ws/ {
        proxy_pass http://wsserver;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
 }

 }