Websocket connections not working inside docker +

Hi, I am using a Django Backend with React frontend… I want to use websockets to connect both ends. I have a docker service to run daphene and nginx to route all “ws/*” to daphene server. Here is the daphene service that i defined in docker:

  websocket:
    build: ./backend
    command: daphne -b 0.0.0.0 -p 8001 core.asgi:application
    volumes:
      - ./backend:/crafter
      - static_volume:/crafter/staticfiles/backend
    environment:
      - DJANGO_SETTINGS_MODULE=core.settings
    ports:
      - "8001:8001"
    networks:
      - crafter_network
    depends_on:
      - db

Here is my nginx

location /ws/ {
        proxy_pass http://websocket:8001/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 86400;
    }

This is my consumer:

class TimelineConsumer(AsyncWebsocketConsumer):
    """
    Handles realtime updates and deletions for timeline items
    """
    
    async def connect(self):
        # Set the group name for this connection
        self.group_name = "timeline"

        # Add this consumer to the group
        await self.channel_layer.group_add(
            self.group_name,
            self.channel_name
        )

        # Accept the WebSocket connection
        await self.accept()


    async def disconnect(self, close_code):
        # Remove this consumer from the group upon disconnection
        await self.channel_layer.group_discard(
            self.group_name,
            self.channel_name
        )

This is how I am connecting to my websocket

  useEffect(() => {
        const ws = new WebSocket("ws://localhost/ws/timeline/");
        ws.onopen = () => {
          console.log('WebSocket connection established.');
        };
    
        ws.onmessage = (event) => {
          console.log('WebSocket message received:', event.data);
        };
    
        ws.onclose = () => {
          console.log('WebSocket connection closed.');
        };
    
        return () => {
          ws.close();
        };
    }, []);

I am getting this error in browser console:
WebSocket connection to 'ws://localhost/ws/timeline/' failed: WebSocket connection closed.

What does your docker logs for that container show? What do the nginx logs show?

THis is the log from nginx:

192.168.32.1 - - [12/Nov/2023:20:35:02 +0000] "GET /ws/timeline/ HTTP/1.1" 500 5 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1" "-"

This is the log from websocket container:

websocket_1      | 192.168.32.7:56652 - - [12/Nov/2023:21:37:16] "WSCONNECTING /timeline/" - -
backend_1        | GET /api/set_csrf/ HTTP/1.1 200 28
websocket_1      | 192.168.32.7:56668 - - [12/Nov/2023:21:37:16] "WSCONNECTING /timeline/" - -
websocket_1      | 2023-11-12 21:37:17,177 ERROR    Exception inside application: No route found for path 'timeline/'.
websocket_1      | Traceback (most recent call last):
websocket_1      |   File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
websocket_1      |     return await application(scope, receive, send)
websocket_1      |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
websocket_1      |   File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 134, in __call__
websocket_1      |     raise ValueError("No route found for path %r." % path)
websocket_1      | ValueError: No route found for path 'timeline/'.
websocket_1      | 2023-11-12 21:37:17,178 ERROR    Exception inside application: No route found for path 'timeline/'.
websocket_1      | Traceback (most recent call last):
websocket_1      |   File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
websocket_1      |     return await application(scope, receive, send)
websocket_1      |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
websocket_1      |   File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 134, in __call__
websocket_1      |     raise ValueError("No route found for path %r." % path)
websocket_1      | ValueError: No route found for path 'timeline/'.
websocket_1      | 192.168.32.7:56652 - - [12/Nov/2023:21:37:17] "WSDISCONNECT /timeline/" - -
websocket_1      | 192.168.32.7:56668 - - [12/Nov/2023:21:37:17] "WSDISCONNECT /timeline/" - -

Hi thanks for the quick reply, here’s what you requested for:

This is the logs from nginx container:

192.168.32.1 - - [12/Nov/2023:20:35:02 +0000] "GET /ws/timeline/ HTTP/1.1" 500 5 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1" "-"

This is the logs from websocket container:

websocket_1      | 192.168.32.7:56652 - - [12/Nov/2023:21:37:16] "WSCONNECTING /timeline/" - -
backend_1        | GET /api/set_csrf/ HTTP/1.1 200 28
websocket_1      | 192.168.32.7:56668 - - [12/Nov/2023:21:37:16] "WSCONNECTING /timeline/" - -
websocket_1      | 2023-11-12 21:37:17,177 ERROR    Exception inside application: No route found for path 'timeline/'.
websocket_1      | Traceback (most recent call last):
websocket_1      |   File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
websocket_1      |     return await application(scope, receive, send)
websocket_1      |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
websocket_1      |   File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 134, in __call__
websocket_1      |     raise ValueError("No route found for path %r." % path)
websocket_1      | ValueError: No route found for path 'timeline/'.
websocket_1      | 2023-11-12 21:37:17,178 ERROR    Exception inside application: No route found for path 'timeline/'.
websocket_1      | Traceback (most recent call last):
websocket_1      |   File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
websocket_1      |     return await application(scope, receive, send)
websocket_1      |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
websocket_1      |   File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 134, in __call__
websocket_1      |     raise ValueError("No route found for path %r." % path)
websocket_1      | ValueError: No route found for path 'timeline/'.
websocket_1      | 192.168.32.7:56652 - - [12/Nov/2023:21:37:17] "WSDISCONNECT /timeline/" - -
websocket_1      | 192.168.32.7:56668 - - [12/Nov/2023:21:37:17] "WSDISCONNECT /timeline/" - -

In case you ar einterested how I am dealing with the routings for websockets in django, here they are:

routing.py

# Set django settings module environment variable
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
django_asgi_app = get_asgi_application()

from timeline.consumers import TimelineConsumer
from api.consumers import SessionConsumer


ws_urlpatterns = [
    path("ws/timeline/", TimelineConsumer.as_asgi()),
    path('ws/sessionstatus/<str:user_hash>/', SessionConsumer.as_asgi()),
]

application = ProtocolTypeRouter({
    'http': django_asgi_app,
    "websocket": URLRouter(ws_urlpatterns),
})

settings.py

# Websockets channels
ASGI_APPLICATION = "core.routing.application"
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer"
    }
}

This is showing to you that nginx is only passing the timeline portion of the request url through the proxy.

I believe you need to change this:

to this:
proxy_pass http://websocket:8001/ws/;

(Or, I believe you could also define it without the trailing slash as:)
proxy_pass http://websocket:8001;

Thank you so much for helping me out with this. Could you clear one thing to me? In the nginx logs why am I seeing “GET /ws/timeline/ HTTP/1.1” ? I thought its an WS route and it shouldnt show a REST Method…

It’s not a REST method. It’s a standard HTTP GET. (A websocket connection is a standard http request that gets upgraded to be a persistent TCP socket.)

ah I had the wrong idea of WS afterall, thanks, i thought of it as MQTT protocols

You could implement something like MQTT on top of a WebSocket, but MQTT assumes the existance of, or the ability to create, a socket.