This is my current configuration on my digital ocean droplet:

This is my current configuration on my digital ocean droplet:

Django, Django Channels, Daphne, Nginx, Gunicorn, HTTPS**

I am stuck trying to configure Redis, Daphne, and Nginx. I used this walkthrough to configure it but I am still having issues:

I was able to successfully deploy my server up to https with the frontend able to successfully connect and interact with the backend.

--------------------------------------Daphne.service------------------------------------


[Unit]
Description=WebSocket Daphne Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/home/user/project
ExecStart=/home/user/project/venv/bin/python /home/user/project/venv/bin/daphne project.asgi:application
Restart=on-failure

[Install]
WantedBy=multi-user.target

----------------------/etc/nginx/sites-available/project--------------------------------

server {
    server_name DomainURL www.DomainURL;

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

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/DomainURL/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/DomainURL/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


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


    if ($host = DomainURL) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


listen 80;
server_name DomainURL www.DomainURL;
return 404; # managed by Certbot
}

-------------------------------(Django) Settings.py-------------------------------------

ALLOWED_HOSTS = ['<server ip>', 'localhost', '127.0.0.1', 'DomainURL', 'www.DomainURL']

ASGI_APPLICATION = "project.asgi.application"

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

CORS_ORIGIN_ALLOW_ALL = True  
CORS_ALLOW_CREDENTIALS = True

----------------------------------(Django) asgi.py--------------------------------------

import os
from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import myApp.routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")

application = ProtocolTypeRouter({
     "http": get_asgi_application(),
     "websocket": AuthMiddlewareStack(
         URLRouter(
             myApp.routing.websocket_urlpatterns
         )
     )
 })

---------------------------------(Django) Routing.py------------------------------------

from django.urls import re_path
from. consumers import ChatConsumer

websocket_urlpatterns = [
    re_path(r'ws/chat/(?P<user_id>\d+)/', ChatConsumer.as_asgi()),
]

-------------------------------(Django) Requirements.txt---------------------------------

asgiref==3.7.2
Django==5.0
django-jazzmin==2.6.0
djangorestframework==3.14.0
djangorestframework-simplejwt==5.3.1
import-export==0.3.1
Pillow==10.1.0
PyJWT==2.8.0
pytz==2023.3.post1
sqlparse==0.4.4
tzdata==2023.3
django-crispy-forms
django-import-export
django-mathfilters
django-taggit
django-ckeditor
django-ckeditor-5

# Additional Django utilities
django-cors-headers
channels
daphne
gunicorn
psycopg2

#db url
dj-database-url

I am trying to connect my frontend to the websocket running on my server using this javascript on the frontend:

--------------------------------frontend file handling websocket actions-----------------------

class WebSocketService {
    private socket: WebSocket | null

    private messageHandler: ((data: any) => void) | null;

    constructor() {
      this.socket = null;
      this.messageHandler = null;
    }

    setMessageHandler(handler: (data: any) => void) {
      this.messageHandler = handler;
    }
  
    connect(url: string) {
      this.socket = new WebSocket(url);
  
      // Connection opened
      this.socket.addEventListener('open', (event) => {
        console.log('WebSocket is connected');

      });

...
  export const websocketService = new WebSocketService();


---------------------frontend file calling websocket functions----------------------------

const wsBaseUrl = 'wss://www.DomainURL';

  if (UserProfile && !isSocketConnected) {
    setisSocketConnected(true)
    const socket = `${wsBaseUrl}/ws/chat/${UserProfile.user_id}/`
    websocketService.connect(socket as any)
  }



*** all code and web socket connections worked as designed in my development environment with my backend being hosted on my local/home network.

I don’t receive any errors when running these commands:

sudo systemctl status gunicorn
sudo systemctl status redis
systemctl status daphne.service
systemctl status on_boot.service

I receive this console error on my frontend application:

WebSocket connection to 'wss://www.DomainURL/ws/chat/2/' failed: There was a bad response from the server.

I have tried modifying the configurations on these files but have not been able to obtain a different result. The goal is to get the frontend to establish a connection with the backend websocket.

One issue that I see right away is that you’ve configured Daphne to serve as an SSL endpoint.

However, your nginx configuration is proxying through a straight (non-ssl) http connection. Nginx is serving as your ssl endpoint, preventing Daphne from needing to do that.

In this general case, this is how you would want to do it. Remove the -e parameter and the cert references from your Daphne run command.

Awesome thanks I’ll give it a try appreciate the help.

Thanks for the advice but it seems that I am still receiving the same failed connection error. I did update the Daphne.service file in my code and in the above post to reflect your recommendations. Thanks again.

The next thing I’ve noticed here is that you’re not passing the /ws/ through the proxy_pass directive for that location. It should be:
proxy_pass http://127.0.0.1:8001/ws/;

Also, when you have errors like this, check your logs for more detailed information. One of the browser’s console log, nginx, or Daphne logs would have more information than just the message you’re quoting.

I think adding /ws/ to the proxy pass modified the websocket path as refrenced in the nginx error log below. Also I noticed daphne.service is logging as listening to port:8000 I’m not sure if that is correct or if it should be listening to port 8001. As for the routing and frontend websocket connection I added the extra “/ws/” to reflect the new path.

sudo journalctl -u daphne.service -f:

Apr 14 14:34:57 project python[1400]: 2024-04-14 14:34:57,087 INFO     Starting server at tcp:port=8000:interface=127.0.0.1
Apr 14 14:34:57 project python[1400]: 2024-04-14 14:34:57,089 INFO     HTTP/2 support not enabled (install the http2 and tls Twisted extras)
Apr 14 14:34:57 project python[1400]: 2024-04-14 14:34:57,089 INFO     Configuring endpoint tcp:port=8000:interface=127.0.0.1
Apr 14 14:34:57 project python[1400]: 2024-04-14 14:34:57,090 INFO     Listening on TCP address 127.0.0.1:8000

sudo tail -f /var/log/nginx/error.log:

2024/04/14 13:57:13 [error] 764#764: *12 connect() failed (111: Connection refused) while connecting to upstream, client: <ip address>>, server: domainURL, request: "GET /ws/ws/chat/2/ HTTP/1.1", upstream: "http://127.0.0.1:8001/ws/ws/chat/2/", host: "www.domainURL"

Based on the error i tried modifying my routing and the websocket address on my frontend:
–routing.py–

websocket_urlpatterns = [
    re_path(r'ws/ws/chat/(?P<user_id>\d+)/', ChatConsumer.as_asgi()),
]

–frontend–

const wsBaseUrl = 'wss://www.DomainURL';

  if (UserProfile && !isSocketConnected) {
    setisSocketConnected(true)
    const socket = `${wsBaseUrl}/ws/ws/chat/${UserProfile.user_id}/`
    websocketService.connect(socket as any)
  }

console logs:

WebSocket connection to 'wss://www.mydomainURL.com/ws/ws/chat/2/' failed: There was a bad response from the server.

It doesn’t matter which one you use, as long as they match each other.

No, this doesn’t get changed anywhere else. The proxy pass directive needs to be changed to pass the /ws/ as part of the uri. It’s not adding an additional /ws/ to the request being proxied. No other change should be made for this.

Thanks @KenWhitesell I was able to solve the issue. I needed to change my configuration so that everything ran on the same port.

This is what I changed:

----------------------/etc/nginx/sites-available/project--------------------------------
Before:

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;
}

After:

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:8000/ws/;
}

This worked for me because my Daphne service was running on port 8000.

For others with a similar issue run this command to verify what you Daphne service is running on:
sudo journalctl -u daphne.service -f