Websocket connection failed(WSREJECT) in production. (Nginx, Gunicorn, Daphne)

Is this supposed to be with nginx? If so, then you want to connect to the nginx port, not the daphne port.

Side note: I don’t handle the websocket myself. I let the ws HTMX extension handle all that for me. It’s been wonderful…

And, if you’re getting any errors, please post all complete error messages - the nginx logs, the daphne logs, and the responses as shown in the browser’s network tab, along with any error messages that may be shown in the browser’s console pane.

Yeah nginx.
Also wanted to know if you attempted the connection with my domain becuase I also tried using htmx

<!DOCTYPE html>
<html>
<head>
    <!-- Include HTMX library -->
    <script src="https://unpkg.com/htmx.org/dist/htmx.min.js"></script>
</head>
<body>
    <button hx-get="/connect_ws" hx-connect="wss://taskitly.com:8001/notification/" hx-trigger="load">Connect to WebSocket</button>
</body>
</html>

I get socket closed

You’re still trying to connect to Daphne instead of nginx. Get rid of the 8001 in the connect and change it to whatever port nginx is listening on.

I’m a little confused, though I tried connecting without specifying the port and still refused the connection.
I had to confirm from nginx conf, port 8001 is what’s directed to daphne.
Nginx is listening through 8001 but I still can’t establish a connection from the browser.
Postman is able to still connect and interact with the websockets endpoints.

What port is nginx listening on?

Nginx is listening on port 8001.
Postman couldn’t connect when I removed the port 8001

No it’s not. Not if Daphne is listening on port 8001. (Or, if it is, then you’ve got a different problem.)

Seems I misunderstood the nginx conf file


server {

    server_name 146.190.21.111 www.taskitly.com api.taskitly.com www.api.taskitly.com taskitly.com;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static {
                autoindex on;
                alias /var/www/taskitly/static/;
                        }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }

    location /ws/ {                              
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_redirect off;
        proxy_pass http://127.0.0.1:8001;
    }
        listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/api.taskitly.com/fullchain.pem; # man>
    ssl_certificate_key /etc/letsencrypt/live/api.taskitly.com/privkey.pem; # m>
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot



        }

        server {
    if ($host = www.api.taskitly.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = api.taskitly.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        server_name 146.190.21.111 api.taskitly.com www.api.taskitly.com;
    listen 80;

}

So please, how do I add another port for daphne?
Okay also checked, port 8001 is not available to nginx

tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      141268/nginx: maste 
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      141268/nginx: maste 
tcp6       0      0 :::80                   :::*                    LISTEN      141268/nginx: maste 

Look at your nginx.conf file.

What are your listen directives in that file?

Those are the ports that nginx is listening on.

This has nothing to do with how nginx communicates with Daphne - that is controlled by the proxy_pass directives.

The whole purpose of using nginx here is that it is a proxy between the “outside world” (browsers) and the “inside world” (Daphne). A browser communicates with nginx. Nginx communicates with Daphne. The browser does not communicate with Daphne.

Okay, it’s only port 80

Look more closely. Also notice what the netstat command was showing you.

Redirecting all interface from port 80 and 443

Not redirecting.

Nginx is listening on port 80 (http and ws) and port 443 (https and wss).

Those are the ports the browser should be communicating with.

okay.
I tried connecting to it without the specifying 8001 but the connection failed.

And the details of this failure? (All the relevent logs and messages)

couldn’t find any registered log request from daphne.service:

 daphne.service - WebSocket Daphne Service
     Loaded: loaded (/etc/systemd/system/daphne.service; disabled; preset: enabled)
     Active: active (running) since Wed 2024-01-10 14:06:13 UTC; 12h ago
   Main PID: 141270 (python)
      Tasks: 3 (limit: 2308)
     Memory: 84.1M
        CPU: 23.832s
     CGroup: /system.slice/daphne.service
             └─141270 /home/taskitly/taskily/venv/bin/python /home/taskitly/taskily/venv/bin/daphne -e ssl:8001:p>

Jan 10 14:06:13 taskitly.com systemd[1]: Started daphne.service - WebSocket Daphne Service.
Jan 10 14:06:14 taskitly.com python[141270]: 2024-01-10 15:06:14,974 INFO     Starting server at ssl:8001:private>
Jan 10 14:06:14 taskitly.com python[141270]: 2024-01-10 15:06:14,976 INFO     HTTP/2 support enabled
Jan 10 14:06:14 taskitly.com python[141270]: 2024-01-10 15:06:14,976 INFO     Configuring endpoint ssl:8001:priva>
Jan 10 14:06:14 taskitly.com python[141270]: 2024-01-10 15:06:14,984 INFO     Listening on TCP address 0.0.0.0:80>
~
~

here’s a python script test:

import websocket
import threading
import time

def on_message(ws, message):
    print(f"Received message: {message}")

def on_error(ws, error):
    print(f"WebSocket error: {error}")

def on_close(ws, close_status_code, close_msg):
    print("WebSocket closed")

def on_open(ws):
    def send_heartbeat():
        while True:
            ws.send("Heartbeat")
            time.sleep(5)

    # Start a thread to send periodic heartbeats
    threading.Thread(target=send_heartbeat, daemon=True).start()

if __name__ == "__main__":
    websocket.enableTrace(True)
    
    # Replace 'wss://example.com/socket' with your WebSocket URL
    ws_url = "wss://taskitly.com/notification"
    
    ws = websocket.WebSocketApp(
        ws_url,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close,
    )
    
    ws.on_open = on_open
    
    # Run the WebSocket in a separate thread
    ws_thread = threading.Thread(target=ws.run_forever, daemon=True)
    ws_thread.start()
    
    # Keep the main thread running to simulate an application
    while True:
        time.sleep(1)

The Response:

-- request header ---
GET /notification HTTP/1.1
Upgrade: websocket
Host: taskitly.com
Origin: https://taskitly.com
Sec-WebSocket-Key: 01sNGWjyUWWPD6B2EDTSxQ==
Sec-WebSocket-Version: 13
Connection: Upgrade


-----------------------
--- response header ---
HTTP/1.1 404 Not Found
Server: nginx/1.24.0 (Ubuntu)
Date: Thu, 11 Jan 2024 02:37:31 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 179
Connection: keep-alive
X-Frame-Options: DENY
Vary: origin
access-control-allow-origin: *
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
-----------------------
WebSocket error: Handshake status 404 Not Found -+-+- {'server': 'nginx/1.24.0 (Ubuntu)', 'date': 'Thu, 11 Jan 2024 02:37:31 GMT', 'content-type': 'text/html; charset=utf-8', 'content-length': '179', 'connection': 'keep-alive', 'x-frame-options': 'DENY', 'vary': 'origin', 'access-control-allow-origin': '*', 'x-content-type-options': 'nosniff', 'referrer-policy': 'same-origin', 'cross-origin-opener-policy': 'same-origin'} -+-+- b'\n<!doctype html>\n<html lang="en">\n<head>\n  <title>Not Found</title>\n</head>\n<body>\n  <h1>Not Found</h1><p>The requested resource was not found on this server.</p>\n</body>\n</html>\n'
Handshake status 404 Not Found -+-+- {'server': 'nginx/1.24.0 (Ubuntu)', 'date': 'Thu, 11 Jan 2024 02:37:31 GMT', 'content-type': 'text/html; charset=utf-8', 'content-length': '179', 'connection': 'keep-alive', 'x-frame-options': 'DENY', 'vary': 'origin', 'access-control-allow-origin': '*', 'x-content-type-options': 'nosniff', 'referrer-policy': 'same-origin', 'cross-origin-opener-policy': 'same-origin'} -+-+- b'\n<!doctype html>\n<html lang="en">\n<head>\n  <title>Not Found</title>\n</head>\n<body>\n  <h1>Not Found</h1><p>The requested resource was not found on this server.</p>\n</body>\n</html>\n' - goodbye
WebSocket closed

What URLs are you proxying through to Daphne?

If I understand, that would be “wss://taskitly.com:8001/notification/”

Look at your nginx configuration. What URLs are going to cause nginx to forward a request through to Daphne?

anyone starting with “/ws/”
like

  • wss://www.taskitly.com/
  • wss://146.190.21.111/
  • wss://api.taskitly.com/
  • wss://www.api.taskitly.com/