通过安全的 websocket WSS 从 Django 项目连接到 Redis/Daphne
Connect via a secure websocket WSS from Django project to Redis/Daphne
我正在尝试将安全的 websocket WSS 与来自我的 Django 项目的 Redis/Daphne 连接:
new WebSocket('wss://myproject.com:9002/ws/myChat/')
但是无法连接。在浏览器控制台中,我总是收到以下错误:
myCode.js:36 WebSocket connection to 'wss://myproject.com:9002/ws/myChat/' failed
这是我看到的唯一错误,例如Nginx (sudo tail -F /var/log/nginx/error.log) 显示没有相关错误。
Daphne 和 Redis 服务似乎有效:
Redis 状态:
redis-server.service - Advanced key-value store
Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-04-07 08:44:07 CEST; 55min ago
Docs: http://redis.io/documentation,
man:redis-server(1)
Process: 281 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=0/SUCCESS)
Main PID: 381 (redis-server)
Tasks: 4 (limit: 60)
Memory: 4.1M
CGroup: /system.slice/redis-server.service
└─381 /usr/bin/redis-server 127.0.0.1:6379
Daphne-服务配置:
[Unit]
Description=WebSocket Daphne Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/home/django_user/appdir/myProject
ExecStart=/home/django_user/appdir/env/bin/python3 /home/django_user/appdir/env/bin/daphne -e ssl:9002:privateKey=/etc/letsencrypt/live/myproject.com/privkey.pem:certKey=/etc/letsencrypt/myproject.com/fullchain.pem myproject.asgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.target
Daphne-服务状态:
daphne_myproject.service - WebSocket Daphne Service
Loaded: loaded (/etc/systemd/system/daphne_myproject.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-04-07 08:44:04 CEST; 50min ago
Main PID: 277 (python3)
Tasks: 1 (limit: 60)
Memory: 74.8M
CGroup: /system.slice/daphne_myproject.service
└─277 /home/django_user/appdir/env/bin/python3 /home/django_user/appdir/env/bin/daphne -e ssl:9002:privateKey=/etc/letsencrypt/live/myproject.com/privkey.pem:certKey=/etc/letsencrypt/live/myproject.com/fullchain.pem myproject.asgi:application
Nginx-配置:
upstream websocket{
server 127.0.0.1:6379;
}
server {
server_name myproject.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/django_user/appdir/myProject;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/myproject.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/myproject.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location /ws {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
if ($host = myproject.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name myproject.com;
return 404; # managed by Certbot
}
在我的 Django 项目中:
settings.py
ASGI_APPLICATION = "myproject.routing.application"
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
routing.py:(在聊天应用程序中,它是我的 Django 项目的一部分,wss://myproject... websocket 已打开)
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
asgi.py:
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_asgi_application()
我是不是漏掉了什么?我现在正在尝试几天,但无法弄清楚问题出在哪里。难道是因为我用的是 root 用户的 Daphne 服务,而不是 django_user?我这样做是因为 django_user 无法访问我在 /etc/letsencrypt/... 中的证书(尽管他有 sudo 权限)。
更新:
刚看到这个错误(在 sudo systemctl status daphne_myproject.service):
Apr 07 19:42:07 myproject.com python3[268]: 2022-04-07 19:42:07,215 ERROR Exception inside application: Django can only handle ASGI/HTTP connections, not websocket.
我刚刚通过如下修改asgi.py解决了我的问题。也许它会帮助其他人解决同样的问题:
import os
import django
from channels.routing import get_default_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
application = get_default_application()
我正在尝试将安全的 websocket WSS 与来自我的 Django 项目的 Redis/Daphne 连接:
new WebSocket('wss://myproject.com:9002/ws/myChat/')
但是无法连接。在浏览器控制台中,我总是收到以下错误:
myCode.js:36 WebSocket connection to 'wss://myproject.com:9002/ws/myChat/' failed
这是我看到的唯一错误,例如Nginx (sudo tail -F /var/log/nginx/error.log) 显示没有相关错误。
Daphne 和 Redis 服务似乎有效:
Redis 状态:
redis-server.service - Advanced key-value store
Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-04-07 08:44:07 CEST; 55min ago
Docs: http://redis.io/documentation,
man:redis-server(1)
Process: 281 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=0/SUCCESS)
Main PID: 381 (redis-server)
Tasks: 4 (limit: 60)
Memory: 4.1M
CGroup: /system.slice/redis-server.service
└─381 /usr/bin/redis-server 127.0.0.1:6379
Daphne-服务配置:
[Unit]
Description=WebSocket Daphne Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/home/django_user/appdir/myProject
ExecStart=/home/django_user/appdir/env/bin/python3 /home/django_user/appdir/env/bin/daphne -e ssl:9002:privateKey=/etc/letsencrypt/live/myproject.com/privkey.pem:certKey=/etc/letsencrypt/myproject.com/fullchain.pem myproject.asgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.target
Daphne-服务状态:
daphne_myproject.service - WebSocket Daphne Service
Loaded: loaded (/etc/systemd/system/daphne_myproject.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-04-07 08:44:04 CEST; 50min ago
Main PID: 277 (python3)
Tasks: 1 (limit: 60)
Memory: 74.8M
CGroup: /system.slice/daphne_myproject.service
└─277 /home/django_user/appdir/env/bin/python3 /home/django_user/appdir/env/bin/daphne -e ssl:9002:privateKey=/etc/letsencrypt/live/myproject.com/privkey.pem:certKey=/etc/letsencrypt/live/myproject.com/fullchain.pem myproject.asgi:application
Nginx-配置:
upstream websocket{
server 127.0.0.1:6379;
}
server {
server_name myproject.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/django_user/appdir/myProject;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/myproject.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/myproject.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location /ws {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
if ($host = myproject.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name myproject.com;
return 404; # managed by Certbot
}
在我的 Django 项目中:
settings.py
ASGI_APPLICATION = "myproject.routing.application"
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
routing.py:(在聊天应用程序中,它是我的 Django 项目的一部分,wss://myproject... websocket 已打开)
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
asgi.py:
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_asgi_application()
我是不是漏掉了什么?我现在正在尝试几天,但无法弄清楚问题出在哪里。难道是因为我用的是 root 用户的 Daphne 服务,而不是 django_user?我这样做是因为 django_user 无法访问我在 /etc/letsencrypt/... 中的证书(尽管他有 sudo 权限)。
更新:
刚看到这个错误(在 sudo systemctl status daphne_myproject.service):
Apr 07 19:42:07 myproject.com python3[268]: 2022-04-07 19:42:07,215 ERROR Exception inside application: Django can only handle ASGI/HTTP connections, not websocket.
我刚刚通过如下修改asgi.py解决了我的问题。也许它会帮助其他人解决同样的问题:
import os
import django
from channels.routing import get_default_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
application = get_default_application()