5

I am currently trying to setup my Django Channels chat app, and I have followed the Docs to the best of my understanding - Obviously when something doesn't go right, there's always a solution, but I am just having difficulties working out where I've gone wrong with getting this to work.

So far I have installed Django Channels, correctly configured my channel_layer within settings.py, I have referenced the docs and other online tutorials with creating my consumer.py file, utils.py, views.py and chat.html template file.

I have also configured nginx, gunicorn, daphne and redis and I can confirm that all of these services are running. I have installed LetsEncrypt and have allowed the SSL port (443 for https connections).

I am currently accessing my Django website on a live production server like this: https://mydomain:8001 and the direct link to my chat is configured as https://mydomain:8001/messenger

(I have allowed port 8001 through my firewall)

Here are the status messages I am getting from the chat page:

SUCCESS {response: "Successfully got the chat.", chatroom_id: 1}chatroom_id: 1response: "Successfully got the chat."__proto__: Object
(index):303 setupWebSocket: 1
(index):371 ChatSocket connecting..
WebSocket connection to 'wss://www.<mydomain>.com:8001/messenger/1/' failed: 
setupWebSocket @ (index):317
success @ (index):389
c @ jquery.min.js
fireWith @ jquery.min.js
l @ jquery.min.js
(anonymous) @ jquery.min.js
ChatSocket error Event {isTrusted: true, type: "error", target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}bubbles: falsecancelBubble: falsecancelable: falsecomposed: falsecurrentTarget: WebSocket {url: "wss://<mydomain>:8001/messenger/1/", readyState: 3, bufferedAmount: 0, onopen: null, onOpen: ƒ, …}defaultPrevented: falseeventPhase: 0isTrusted: truepath: []returnValue: truesrcElement: WebSocket {url: "wss://<mydomain>:8001/messenger/1/", readyState: 3, bufferedAmount: 0, onopen: null, onOpen: ƒ, …}target: WebSocket {url: "wss://<mydomain>:8001/messenger/1/", readyState: 3, bufferedAmount: 0, onopen: null, onOpen: ƒ, …}timeStamp: 43973.62500001327type: "error"__proto__: Event
(index):357 Chat socket closed.

Any help with troubleshooting this issue would be greatly appreciated. If you could advise on which files you should prefer to see, I will happily update my question with the contents of any requested files for my chat app. :-)

Thank you!

File Contents:

nginx.conf

server {
    listen 80;
    server_name myapp mydomain.com www.mydomain.com;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/myapp;
    }

    location / {
        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-Forwarded-Proto $scheme;
        proxy_pass http://unix:/home/myapp/myapp.sock;
    }
    
    location /ws/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_redirect off;
        proxy_pass https://127.0.0.1:8001;
    }
    
    location /wss/ {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_pass http://127.0.0.1:8001;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}

routing.py

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.urls import path, re_path

from messenger.consumers import ChatConsumer


application = ProtocolTypeRouter({
    'websocket': AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                
                    path('messenger/<room_id>/', ChatConsumer),
                    
            ])
        )
    ),
})

settings.py

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

Error I am receiving within Console: (index):317 WebSocket connection to 'wss://www.mydomain.com:8001/messenger/1/' failed:

(Where it says mydomain.com, my actual domain is typed in there :)

Latest Daphne Logs from journalctl

Jun 21 14:22:56 myhostname.com python3[36088]: 2021-06-21 14:22:56,576 INFO     Starting server at ssl:8001:privateKey=/etc/letsencrypt/live/mydomain.com/privkey.pem:certKey=/etc/let>
Jun 21 14:22:56 myhostname.com python3[36088]: 2021-06-21 14:22:56,576 INFO     HTTP/2 support not enabled (install the http2 and tls Twisted extras)
Jun 21 14:22:56 myhostname.com python3[36088]: 2021-06-21 14:22:56,577 INFO     Configuring endpoint ssl:8001:privateKey=/etc/letsencrypt/live/mydomain.com/privkey.pem:certKey=/etc/l>
Jun 21 14:22:56 myhostname.com python3[36088]: 2021-06-21 14:22:56,584 INFO     Listening on TCP address 0.0.0.0:8001

Error in Daphne Log

Jun 21 14:38:51 myhostname.com python3[36088]: Traceback (most myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/routing.py", line 71, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await application(scope, receive, send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/security/websocket.py", line 37, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await self.application(scope, send, receive)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/sessions.py", line 47, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await self.inner(dict(scope, cookies=cookies), receive, send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/sessions.py", line 254, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await self.inner(wrapper.scope, receive, wrapper.send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/auth.py", line 181, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await super().__call__(scope, receive, send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/middleware.py", line 26, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await self.inner(scope, receive, send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/routing.py", line 160, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     send,
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/asgiref/compatibility.py", line 33, in new_application
Jun 21 14:38:51 myhostname.com python3[36088]:     instance = application(scope)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/generic/websocket.py", line 159, in __init__
Jun 21 14:38:51 myhostname.com python3[36088]:     super().__init__(*args, **kwargs)
Jun 21 14:38:51 myhostname.com python3[36088]: TypeError: object.__init__() takes no parameters

4
  • 1
    Hi there. Hmm, it's really hard to tell from where to start. Do you have an appropriate config for the websocket connection in the nginx? Also, do you have domain with www. configured? Check the daphe logs - does the request reach the backend or not? Maybe you could see any errors there. Also, check the devtools in your browser - does it state the reason of the connection failure? Probably attach the relevant nginx config, and also django asgi routing Commented Jun 17, 2021 at 19:21
  • Hello Alexandr, I've only just seen your response. Thank you so much for responding! :-) I will update my question with the websocket config in nginx, along with the routing.py - There isn't any reason given for the connection failure - The only error printed in the console is "Websocket connection to wss://mydomain:8001/ failed. - Which is where i'm struggling as the error is generic and not all that helpful haha! :-) Commented Jun 17, 2021 at 21:39
  • I have now updated my original question with the contents of both files you have requested :-) and the exact error I am receiving within the console. Commented Jun 17, 2021 at 22:15
  • Raspberry Pi 4: One solution, the only solution (for me) that worked was to simply restart the Pi4, ssh into it, run a systemctl status redis-server to see that Redis-server is running at startup, and then restarting all my IDE's on my Workstation (Wingware). Start back up my django site on 0.0.0.0:800x then the MainApp that connects to it over a websocket. Now it's connecting /communicating again. So essentially the solution was to restart the Pi4. Commented Apr 20, 2024 at 20:47

3 Answers 3

8

I think the issue is in the configuration. In the nginx, you have to specify the URL prefix, not the protocol, there is also no need to add both ws and wss. The nginx config must look similar to this

location /ws/ {
    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-Forwarded-Host   $server_name;
    proxy_set_header X-Forwarded-Proto  $scheme;
    proxy_set_header X-Url-Scheme       $scheme;
    proxy_redirect off;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_pass http://127.0.0.1:8001;
}

So, to connect via a Websocket protocol, you have to access something under wss://www.<mydomain>.com:8001/ws/. For this to work, your asgi routes have to also include the ws prefix. Also, you should use as_asgi()on the consumer. (https://channels.readthedocs.io/en/stable/topics/routing.html)

application = ProtocolTypeRouter({
    'websocket': AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                    path('ws/messenger/<room_id>/', ChatConsumer.as_asgi()), 
            ])
        )
    ),
})

Now you should be able to connect to wss://www.<mydomain>.com:8001/ws/messenger/1/ (don't forget the ws!).

Sign up to request clarification or add additional context in comments.

11 Comments

Ahh thank you so much! I'm going to test this solution now and thank you for giving up your time to explain this to me, it makes perfect sense!! I'll provide an update this afternoon with the outcome :-)
So I've tested out your solution - I'm still getting the same error as before with the failed websocket connection. Here's the error i am getting with the updates link directing to /ws/ (index):317 WebSocket connection to 'wss://www.mydomain.com/ws/messenger/1/' failed.
Sorry - Just to add to my last comment, I missed the :8001 port on the Websocket link, i've added this in although, I'm still receiving the Websocket connection failed error - Updated error: (index):317 WebSocket connection to 'wss://www.mydomain.com:8001/ws/messenger/1/' failed:
I'm not too sure whether this could be a factor of what's creating the connection issue, but I read online that the asgi.py file permission should be set as the "django" user. I've checked on my file system and the user which owns the file currently is nginx:ninx, not sure if this could be a potential issue? :-)
Did you check the daphne logs as I asked in the comment? Does the request ever reach daphne? Is it running? Also check for errors in the nginx log. If there is an issue with permission, you won't be able to start Daphne, also the user you need to use would be specific for your setup, there is no "magic" django user for everyone's server
|
0

Finally got Django Channels working (Finally managed to get my Websocket connection working) - With many thanks to Alexandr for his assistance.

From the logs, I found the following error: ERROR: TypeError: object.__init__() takes exactly one argument (the instance to initialize)

I forgot to append as_asgi() to the end of where I was calling my ChatConsumer. So I changed my routing path from:

path('ws/messenger/<room_id>/', ChatConsumer),

TO

path('ws/messenger/<room_id>/', ChatConsumer.as_asgi()),

And my Websocket is now open and has successfully connected! Happy days!

A big thank you again for all your help Alexandr!

3 Comments

Wow, that one was easy to miss. Please accept my answer if I was able to help
Thank you Alexandr, I have accepted your answer!! :-)
(It might be worth updating your answer with the routing path I adjusted) :-) I tried to suggest an edit, but I was getting an error on StackOverflow which mentioned that the "Suggested edit queue is full".
0
    proxy_pass http://localhost:10001;
    proxy_set_header Host $host;
    # WebSocket support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    # ...other WebSocket settings

1 Comment

Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. Would you kindly edit your answer to include additional details for the benefit of the community?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.