我们有一个应用程序,使用通道包和工作正常…在本地主机上。当我们进入暂存阶段并在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正在创建一个unix套接字,nginx拾取它进行通信:daphne main.asgi:channel_layer -u /tmp/daphne.sock
我遇到了完全相同的问题。我无法通过unix套接字进行连接,但我发现了一种非常简单的方法,即使用系统端口来实现请求管理。我使用了下面的教程(并使用了我使用Gunicorn的经验),并设法修改了一些他们的Nginx配置文件,我建议你看看这些教程:
-
Django Channels Group Pt1
-
Django channel Group Pt2
My Nginx file
# 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服务的,但如果你真的需要使用套接字,这个配置可能会帮助你。
注意事项
请记住,这个Nginx文件允许Daphne在一般情况下连接,但在生产服务器中,你需要分别运行"Daphne实例服务器"one_answers"Daphne Workers"才能通过你的通道传输消息。
检查您是否使用Redis-Server或其他队列管理器来为您的通道和组提供服务。我这样说是因为我注意到,当使用"InMemory"配置时,多条消息丢失。
还要检查您的生产环境是否将Redis-Server作为守护进程运行。我注意到在一些系统中Redis-Server甚至不能工作,但是Django应用程序在连接被拒绝时没有引发异常。
你需要一些东西来保持Daphne和它的工作,因为即使它们循环,它们也不是"异常抵抗"的,所以当异常被引发时它们会死亡。显然,我建议使用Supervisor或Linux系统进行服务。
我不知道达芙妮的工作人员是否可以在
DEBUG==False
时提供静态和媒体文件,但显然是更好的方法是使用Nginx配置分别服务它们。我仍然不知道使用端口与使用套接字相比的安全/性能影响,所以值得检查(阅读下面,我发现Daphne或我的配置可能存在错误)。
我知道这对你来说可能无关紧要,(我的意思是已经快一个月了)但也许有人会发现这个答案有些用处。
未知且非常奇怪的安全问题
TL;DR:不要用这个配置在同一台服务器上部署两个Django-Daphne应用程序,否则你会很难受的。
通过使用这种配置,我已经能够将Phoenix应用程序与Django应用程序一起部署而没有任何问题,但是当使用这种类型的配置部署2个或更多的Django应用程序时,我遇到了一些问题。由于某种原因,Daphne知道它必须不断读取哪些端口以接收请求,但它只是读取所有端口并将它们提供给它喜欢的任何人。例如,如果我有DJANGO_APP_1
和DJANGO_APP_2
在同一台服务器上运行(具有不同的Nginx配置和明显不同的系统端口),有时DJANGO_APP_2
的Daphne worker会窃取用于DJANGO_APP_1
的请求,反之亦然。我还不能确定问题的根源,但我相信这与达芙妮的工人在某种程度上对他们相关的项目不知情有关。(这只是一个理论,我没有时间检查他们的代码)。
我正在与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";
}
}
}