Django Channels与Nginx配合使用,客户端未收到任何消息

6
我们有一个使用channels包的应用程序,在本地主机上运行得很好。但是,在转移到暂存环境并在Django(带有SSL)前面放置nginx盒子后,我们可以连接到套接字,但客户端无法接收任何消息。
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;
    }
}
运行在上,对于,我升级了一个服务器。我可以在日志中看到我的客户端正在连接,但是仍然无法接收到来自发送到客户端的消息。 创建了一个,选取这个socket进行通信: daphne main.asgi:channel_layer -u /tmp/daphne.sock
2个回答

8
我遇到了完全相同的问题。我无法通过Unix套接字连接,但我找到了一种非常简单的方法来使用系统端口来实现请求管理。我使用了以下教程(并利用了我的Gunicorn经验),并成功地修改了他们的Nginx配置文件,我建议你查看这些教程:

我的Nginx文件

# Enable upgrading of connection (and websocket proxying) depending on the
# presence of the upgrade field in the client request header
map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

# Create an upstream alias to where we've set daphne to bind to
upstream django_app_server {
  server 127.0.0.1:8000;
}

server {
  listen 80;
  server_name YOURDOMAIN.COM;

  client_max_body_size 4G;
  access_log /webapps/General/logs/nginx-access.log;
  error_log /webapps/General/logs/nginx-error.log;

  location /static/ {
      alias /webapps/General/DjangoProject/static/;
  }

  location /media/ {
      alias /webapps/General/DjangoProject/media/;
  }

  location / {
    if (!-f $request_filename) {
        proxy_pass http://django_app_server;
        break;
    }
    # Require http version 1.1 to allow for upgrade requests
    proxy_http_version 1.1;
    # We want proxy_buffering off for proxying to websockets.
    proxy_buffering off;
    # http://en.wikipedia.org/wiki/X-Forwarded-For
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # enable this if you use HTTPS:
    # proxy_set_header X-Forwarded-Proto https;
    # pass the Host: header from the client for the sake of redirects
    proxy_set_header Host $http_host;
    # We've set the Host header, so we don't need Nginx to muddle
    # about with redirects
    proxy_redirect off;

    # Depending on the request value, set the Upgrade and
    # connection headers
    proxy_set_header Upgrade $http_upgrade;

    proxy_set_header Connection $connection_upgrade;
  }

  # Error pages
  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root /webapps/General/DjangoProject/templates/;
  }
}

我的项目中的Websockets(组和通道)运行得非常好,所有请求都由Daphne提供服务,但如果你真的需要使用socket,这个配置可能会对你有所帮助。
需要考虑的要点:
- 请记住,此Nginx文件允许Daphne进行一般连接,但在生产服务器上,您需要分别运行“Daphne Instance Server”和“Daphne Workers”,以便能够通过通道传输消息。 - 检查是否在为通道和组提供服务时使用Redis-Server或其他队列管理器。我之所以这样说是因为我注意到在使用“InMemory”配置时,多条消息丢失了。 - 还要检查您的生产环境是否作为守护程序运行Redis-Server。我注意到,在几个系统中,Redis-Server甚至没有工作,但当拒绝连接时,Django应用程序并没有引发异常。 - 您需要某种方法来保持Daphne及其工作人员的稳定性,因为即使它们循环,它们也不具备“异常抵抗力”,因此当出现异常时它们将停止。显然,我建议使用Supervisor或使用Linux系统作为服务。 - 我不知道daphne的工作人员是否可以在DEBUG==False时提供静态和媒体文件,但显然最好使用Nginx配置单独提供它们。 - 我仍然不知道使用端口与使用socket相比的安全/性能影响,因此值得检查(请参阅下文,我发现了Daphne或我的配置可能存在的错误)。
我知道这对你现在来说可能不相关(我的意思是已经过去了近1个月),但也许有人会发现这个答案有用。
未知和相当奇怪的安全问题
简而言之:不要使用此配置在同一服务器上部署两个Django-Daphne应用程序,否则您将会遇到麻烦。
使用此配置,我已经成功地将Phoenix应用程序与Django应用程序一起部署,没有任何问题,但是当部署2个或更多使用此类型配置的Django应用程序时,我遇到了问题。由于某种原因,Daphne知道它必须不断读取哪些端口以接收请求,但它只是读取所有端口并将它们提供给任何想要的人。例如,如果我在同一服务器上运行DJANGO_APP_1DJANGO_APP_2(具有不同的Nginx配置和显然不同的系统端口),则DJANGO_APP_2的Daphne Workers有时会窃取为DJANGO_APP_1准备的请求,反之亦然。我无法确定问题的根源,但我认为它与Daphne工作人员在某种程度上不关心他们所涉及的项目有关。(只是一种理论,我没有时间检查他们的代码)。

抱歉多次删除和编辑...我只是需要核实我所写的内容。 - Daniel Ortiz

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";
    }
 }

 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接