Deploying Django Channels (Daphne + Supervisor + Nginx) Get

Hi All, I am currently facing trouble deploying Django Channels using Daphne and NGINX. I have test my code while debugging, and it is working. But when I connect it through NGINX then my connection failed. Here is how I am doing it.

asgi.py

import os

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

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gml_admin.settings')
django_asgi_application = get_asgi_application()

from .routing import websocket_urlpatterns

# Django Channels WebSocket application
application = ProtocolTypeRouter(
    {
        "http": django_asgi_application,
        "websocket": AuthMiddlewareStack(
                URLRouter(websocket_urlpatterns)
            ),
    }
)

routing.py

from django.urls import path

from admin_app.consumers import ChatConsumer, PaymentConsumer, TestConsumer
from store.consumers import TransactionConsumer

websocket_urlpatterns = [
    path('ws/payment/', PaymentConsumer.as_asgi()),
    path('ws/store/transaction/<str:username>/', TransactionConsumer.as_asgi()),
    path('ws/test/', TestConsumer.as_asgi()),
]

admin_app/consumers.py

from channels.consumer import AsyncConsumer
from channels.generic.websocket import WebsocketConsumer
import asyncio

class TestConsumer(AsyncConsumer):
    async def websocket_connect(self, event):
        self.connected = True
        await self.send({
            "type": "websocket.accept"
        })

        idx=1
        while self.connected:
            await asyncio.sleep(2)
            
            await self.send({
                'type': 'websocket.send',
                'text': f'current index: {idx}',
            }) 

            idx += 1  

    async def websocket_receive(self, event):
        print("receive", event)

    async def websocket_disconnect(self, event):
        print("disconnected", event)
        self.connected = False        

To test the code I run following command:

daphne -p 8001 -b 0.0.0.0 gml_admin.asgi:application

and create local html file to connect to my server using websocket with following code:

test_ws.html

<html>

<head>
  <script>
	let webSocket = new WebSocket('ws://47.237.x.x:8001/ws/test/');
    let el;

    webSocket.onmessage = (event) => {
		console.log(event.data);
		el = document.getElementById('time');
		el.innerHTML = 'Current time on server is: ' + event.data;
    };
  </script>s
</head>

<body>
  <p id="time"></p>
</body>

</html>

and it is working, but then I want to deploy it and follows the official documentation using Supervisor Deploying — Channels 4.0.0 documentation. Here are my Supervisor and Nginx configuration:

/etc/supervisor/conf.d/gml_admin_asgi.conf

[fcgi-program:asgi]
# TCP socket used by Nginx backend upstream
socket=tcp://localhost:8001

# Directory where your site's project files are located
directory=/home/ecs-user/gml_admin/

# Each process needs to have a separate socket file, so we use process_num
# Make sure to update "mysite.asgi" to match your project name
command=/home/ecs-user/web_env/bin/daphne -u run/daphne/daphne%(process_num)d.sock --fd 0 --access-log - --proxy-headers gml_admin.asgi:application -v 3

# Number of processes to startup, roughly the number of CPUs you have
numprocs=1

# Give each process a unique name so they can be told apart
process_name=asgi%(process_num)d

# Automatically start and recover processes
autostart=true
autorestart=true

# Choose where you want your log to go
stdout_logfile=/home/ecs-user/gml_admin/logs/asgi.log
redirect_stderr=true

/etc/nginx/sites-available/gml_admin

upstream gml_admin {
   server unix:/home/ecs-user/gml_admin/run/gunicorn.sock;
}

upstream daphne {
   #server unix:/tmp/daphne.sock;
   #server unix:/home/ecs-user/gml_admin.sock;
   server localhost:8001;
}

server {
    listen 8000;

    # add here the ip address of your server
    # or a domain pointing to that ip (like example.com or www.example.com)
    server_name www.admin.gracexx.com admin.gracexx.com;

    keepalive_timeout 5;
    client_max_body_size 4G;

    access_log /home/ecs-user/gml_admin/logs/nginx-access.log;
    error_log /home/ecs-user/gml_admin/logs/nginx-error.log;

    location /staticfiles/ {
        root /var/www/gml_admin/;
    }

     location / {
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header Host $http_host;
         proxy_redirect off;
         proxy_pass http://unix:/home/ecs-user/gml_admin/run/gunicorn.sock;
         proxy_send_timeout 300;
         proxy_read_timeout 300;
    }

    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/ws/;
      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-Host $server_name;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/admin.gracexx.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/admin.gracexx.com/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
}

But then when I change my websocket connection to ws://admin.gracexx.com:8001 it failed to connect.

test_ws.html

<html>

<head>
  <script>
    let webSocket = new WebSocket('ws://admin.gracexx.com:8001/ws/test/');
    let el;

    webSocket.onmessage = (event) => {
		console.log(event.data);
		el = document.getElementById('time');
		el.innerHTML = 'Current time on server is: ' + event.data;
    };
  </script>s
</head>

<body>
  <p id="time"></p>
</body>

</html>

I have already try changing ws with wss but it still failed to connect.

You have nginx listening on port 8000, that’s what your JavaScript should be connecting to. It’s going to proxy the connection through to port 8001. (There may be other errors,but this is the first one I noticed.)

My bad, so in my local testing application I no longer need to connect to wss://admin.gracexx.com:8001 instead I can just directly connect to wss://admin.gracexxcom right ?

Assuming you have your DNS entry correct and aside from the typo, yes.

Yes I tried, and it is successfully connect. I no longer need to connect to port 8001. Such a stupid question I am asking :sweat_smile:

Thank You so much Ken ! you save my day