so I am using Ubuntu 18.04.3 LTS, Django 3.0.0, Python 3.6, Nginx, Daphne, docker, Channels for a chat project on AWS EC2 instance. I started a project like the tutorial from Channels. I'm trying to build websocket connection via wss protocol. Everything works great when host is http and websocket connection is ws protocol. But error if host is https and websocket connection is wss protocol. The error as below.
(index):16 WebSocket connection to 'wss://mydomain/ws/chat/1/' failed: Error during WebSocket handshake: Unexpected response code: 404
I'm running my django aspi app by Daphne. Using Channels-redis as channel layer. And run redis by docker. Here's how I run my app server:
daphne -u /home/ubuntu/virtualenvs/src/werewolves/werewolves.sock werewolves.asgi:application
sudo docker run --restart unless-stopped -p 6379:6379 -d redis:2.8
My channel_layers in settings.py in django project.
#settings.py
...
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": ["127.0.0.1",6379],
"symmetric_encryption_keys": ["mykey"],
},
}
}
...
Here's my nginx setting:
upstream websocket {
server unix:/home/ubuntu/virtualenvs/src/werewolves/werewolves.sock;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name mydomain;
location = /favicon.ico { access_log off; log_not_found off; }
location ^~ /static/ {
autoindex on;
alias /home/ubuntu/virtualenvs/static/static-only/; #STATIC_ROOT
}
# SSL settings
ssl on;
listen 443 ssl http2;
listen [::]:443 ssl http2 default_server;
ssl_certificate /etc/letsencrypt/live/mydomain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/mydomain/fullchain.pem;
ssl_session_timeout 10m;
ssl_session cache shared:SSL:1m;
location / {
# proxy setting for django using wsgi
include proxy_params;
#proxy_pass 0.0.0.0:8000;
proxy_pass websocket;
# CORS config. settings for using AWS S3 serving static file
set $origin '*'; #origin url;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK
# with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Co$
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' $origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Co$
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' $origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Co$
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
location ^~ /ws/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://websocket;
}
location ~* \.(js|css)$ {
expires -1;
}
}
Here's my routing.py.
# mysite/routing.py
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import gameroom.routing
application = ProtocolTypeRouter({
# (http->django views is added by default)
'websocket': AuthMiddlewareStack(
URLRouter(
gameroom.routing.websocket_urlpatterns
)
),
})
# chat/routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r'^ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer),
]
And here's how I run my app.
This JS websocket command works with URL: http://mydomain/chat/1/
var chatSocket = new WebSocket('ws://' + window.location.host + '/ws/chat/1/');
The problem is that this JS websocket command doesn't work with URL: https://mydomain/chat/1/
var chatSocket = new WebSocket('wss://' + window.location.host + '/ws/chat/1/');
The error message from browser is:
(index):16 WebSocket connection to 'wss://mydomain/ws/chat/1/' failed: Error during WebSocket handshake: Unexpected response code: 404
Daphne returns below message.
None - - [23/Dec/2019:10:07:05] "GET /chat/1/" 200 1413
Not Found: /ws/chat/1/
2019-12-23 10:07:06,504 WARNING Not Found: /ws/chat/1/
None - - [23/Dec/2019:10:07:06] "GET /ws/chat/1/" 404 2083
How should I modify my Nginx setting? By the way, I don't have a ELB(load balancer) for my AWS EC2 instance.