Django Websockets connect with WS but when using WSS fails to connect

I had it working once before with a demo, but I had to reset my entire box and lost that data/config as to what made it work. I am just using basic websockets to make a connection but I cannot for the life of me figure out what one little piece I am missing to make my websockets connect with websocket secure. I’ve looked at every other topic and solution and have tried nearly every configuration.
daphne command(s) I have used:

daphne -b 0.0.0.0 -p 8001 website.asgi:application
daphne -e ssl:8001:privateKey=/home/website/ssl/website.key:certKey=/home/website/ssl/website.crt website.asgi:application

asgi.py

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'website.settings')
django_asgi_app = get_asgi_application()

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from chatrooms import routing

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

settings.py

from pathlib import Path
import environ
import os

env = environ.Env()
environ.Env.read_env()

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
MASTER_BASE_DIR = os.path.dirname(__file__)

SECRET_KEY = env('SECRET_KEY')

DEBUG = False

ALLOWED_HOSTS = ['www.website.com', 'website.com']
# SECURE_CROSS_ORIGIN_OPENER_POLICY = None
# SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 60
# Application definition

INSTALLED_APPS = [
    'account.apps.AccountConfig',
    'cards.apps.CardsConfig',
    'login.apps.LoginConfig',
    'home.apps.HomeConfig',
    'chatrooms.apps.ChatroomsConfig',
    'daphne',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "django_bootstrap5"
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'website.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(MASTER_BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

ASGI_APPLICATION = 'website.asgi.application'
WSGI_APPLICATION = 'website.wsgi.application'

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

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': env('DB_NAME'),
        'USER': env('DB_USER'),
        'PASSWORD': env('DB_PASS'),
        'HOST': env('DB_HOST'),
        'PORT': env('DB_PORT')
    }
}

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True

STATIC_URL = '/static/'
STATIC_ROOT = "/home/website/Website/static/"

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

nginx config

server {
    listen 443 ssl;
    ssl_certificate /home/website/ssl/website.crt;
    ssl_certificate_key /home/website/ssl/website.key;
    server_name www.website.com website.com;

    location /static/ {
        alias /home/website/Website/static/;
    }

    location /media/ {
	    alias /home/website/Website/media/;
    }

    location /notification/ {
	    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;
    }

    location / {
        proxy_pass http://unix:/run/gunicorn.sock;
	    proxy_http_version 1.1;
	    proxy_set_header Upgrade $http_upgrade;
	    proxy_set_header Connection "Upgrade";	
	    proxy_set_header Host $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;
    }
}

websocket creation
new WebSocket("wss://" + window.location.host + `/notification/`);

If I transition the connection back to http and ws on port 80 everything connects, but nothing is working for https and wss. Any help is extremely appreciated.

You only need the first one of these. Your nginx proxy configuration is not forwarding an ssl connection.

Based on the location /notification/ directive, I believe this:

may need to be proxy_pass http://127.0.0.1:8001/notification/;, depending upon your routing configuration.

If these don’t resolve this, please post as much error-related information as you have available. This would include the access and error logs from nginx for the websocket requests, the daphne logs, and the browser console logs from where the connection is being attempted.

Hey @KenWhitesell

Tried that quick adjustment and it managed to finally hit daphne. Now it’s saying there’s no route in my routing.py to manage it. Do I need to change my path to have a regex string? (or at least thats what I think it is?)

routing.py

from django.urls import path, include
from chatrooms.consumers import ChatConsumer, NotificationConsumer

websocket_urlpatterns = [
    path('chats/', ChatConsumer.as_asgi()),
    path("notification/", NotificationConsumer.as_asgi())
]

Please post the complete error (with traceback if any).

This is the output of systemctl status daphne.service when I try to connect to the websocket

Apr 01 16:12:03 jpmini-server python[3577]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Apr 01 16:12:03 jpmini-server python[3577]: File “/home/website/venv/lib/python3.11/site-packages/channels/auth.py”>
Apr 01 16:12:03 jpmini-server python[3577]: return await super().call(scope, receive, send)
Apr 01 16:12:03 jpmini-server python[3577]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Apr 01 16:12:03 jpmini-server python[3577]: File "/home/website/venv/lib/python3.11/site-packages/channels/middlewa>
Apr 01 16:12:03 jpmini-server python[3577]: return await self.inner(scope, receive, send)
Apr 01 16:12:03 jpmini-server python[3577]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Apr 01 16:12:03 jpmini-server python[3577]: File "/home/website/venv/lib/python3.11/site-packages/channels/routing.>
Apr 01 16:12:03 jpmini-server python[3577]: raise ValueError(“No route found for path %r.” % path)
Apr 01 16:12:03 jpmini-server python[3577]: ValueError: No route found for path ‘notification’.

What does nginx see as the connecting url? (What is your current proxy_pass configuration for this?)

What does the browser show as the url being used to issue the connection?

What I see that I find curious is that the route being shown doesn’t include the trailing slash, while your path directive does define the path as having that slash. So my current conjecture is that either the url being requested isn’t being requested with that slash, or something is dropping it along the way.

Also, the routing.py file you show above - which directory is that in?

Wow. Just wow. That 1 little / changed everything. My Proxy Pass is now:

proxy_pass http://127.0.0.1:8001/notification/;

It has given me the status of connected successfully.
Thank you @KenWhitesell, I will be double checking to make sure it is properly working but I’m just glad it connected over wss.