【问题标题】:Django channels with nginx no messages received by clients带有 nginx 的 Django 频道没有客户端收到消息
【发布时间】:2017-02-01 15:15:09
【问题描述】:

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

Nginx 配置:

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 正在创建一个 nginx 用来通信的 unix 套接字: daphne main.asgi:channel_layer -u /tmp/daphne.sock

【问题讨论】:

    标签: nginx websocket django-channels


    【解决方案1】:

    我遇到了完全相同的问题。我无法通过 unix-socket 进行连接,但我找到了一种非常简单的方法来使用系统端口来实现请求管理。我使用了以下教程(并使用了我对 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/;
      }
    }
    

    我项目中的 websocket 运行良好(组和通道),所有请求都由 Daphne 处理,但如果您真的需要使用套接字,此配置实际上可能对您有所帮助。

    需要考虑的要点

    • 请记住,这个 Nginx 文件通常允许 Daphne 进行连接,但在生产服务器中,您需要分别运行“Daphne Instance Server”和“Daphne Workers”才能通过您的通道传输消息。

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

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

    • 您需要一些东西来保持 Daphne 及其工作人员的正常运行,因为即使它们循环,它们也不是“抗异常”的,因此它们会在引发异常时死亡。显然我推荐使用 Supervisor 或使用 Linux 系统进行服务。

    • 我不知道 daphne 的工作人员是否可以在 DEBUG==False 时提供静态和媒体文件,但显然使用 Nginx 配置单独提供它们会更好。

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

    我知道这对您现在可能无关紧要,(我的意思是已经快 1 个月了)但也许有人会发现这个答案有一些用处。

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

    TL;DR:不要使用此配置在同一台服务器上部署两个 Django-Daphne 应用程序,否则您会遇到麻烦。

    通过使用这种配置,我已经能够将 Phoenix 应用程序与 Django 应用程序一起部署而没有任何问题,但是在使用这种类型的配置部署 2 个或更多 Django 应用程序时我遇到了问题。出于某种原因,Daphne 知道它必须不断读取哪些端口才能接收请求,但它只是读取所有端口并将它们提供给它喜欢的任何人。例如,如果我在同一台服务器上运行DJANGO_APP_1DJANGO_APP_2(具有不同的Nginx 配置和明显不同的系统端口),有时DJANGO_APP_2 的Daphne Workers 会窃取用于DJANGO_APP_1 的请求和反之亦然。我无法查明问题的根源,但我相信这与达芙妮工人在某种程度上不知道他们所涉及的项目有关。 (只是一个理论,我没有时间检查他们的代码)。

    【讨论】:

    • 对多次删除和编辑感到抱歉...我只需要对我所写的内容进行事实检查
    【解决方案2】:

    我正在使用 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";
        }
     }
    
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-23
      • 1970-01-01
      • 1970-01-01
      • 2021-12-22
      • 2021-04-08
      • 1970-01-01
      相关资源
      最近更新 更多