'Django channels rest framework don't return data of subscription in production environment (gunicorn/daphne/nginx)

Hi everyone I deployed django with channels via daphne for websocket and gunicorn for normal request http with reverse proxy nginx, I have a problem that has no answer, it works correctly locally. I used the django library djangochannelsrestframework: djangochannelsrestframework to receive variations on ORM models via websocket

I use this version of django,channels.

  1. django==3.0.8
  2. djangochannelsrestframework==0.1.0
  3. channels==2.4.0
  4. daphne==2.5.0
  5. gunicorn==20.0.4

consumer.py

import json

from channels.generic.websocket import WebsocketConsumer
from djangochannelsrestframework.observer.generics import ObserverModelInstanceMixin
from app_mobile.API.Client.Utente.serializer import UserSerializer
from app_mobile.API.Client.Azienda.serializer import AziendaObserverSerializer
from app_mobile.API.Client.Ordini.serializer import OrdineConsumerSerializer
from app_mobile.models import Azienda, Ordine, User
from djangochannelsrestframework import permissions
from djangochannelsrestframework.generics import GenericAsyncAPIConsumer

class AziendaObserver(ObserverModelInstanceMixin, GenericAsyncAPIConsumer):
   queryset = Azienda.objects.all()
   serializer_class = AziendaObserverSerializer
   permission_classes = (permissions.AllowAny,)

routing.py

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            path("ws/observer/azienda/", AziendaObserver)
        ]),
    ),
})

nginx

# Enable upgrading of connection (and websocket proxying) depending on the
# presence of the upgrade field in the client request header
map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

server {
    listen xx.it:80;
    server_name xx.it  www.xx.it;

    return 301 https://xx.it$request_uri;
}

server {
    listen xx.it:443 ssl http2;
    server_name xx.it www.xx.it;
    charset utf-8;

    access_log /var/log/nginx/xx.it.access.log;
    error_log /var/log/nginx/xx.it.com.error.log;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/django/xx/;
        expires 1M;
        access_log off;
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    }

    location / {
        proxy_pass http://0.0.0.0:8000;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_redirect off;
    }

    location /ws/ {
        proxy_pass http://0.0.0.0:8443;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    ssl_protocols TLSv1.2;
    ssl_certificate /etc/letsencrypt/live/xx.it/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/xx.it/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
}

gunicorn.service

Description=gunicorn
After=network.target


[Service]
PIDFile=/run/gunicorn/pid
User=django
Group=www-data
WorkingDirectory=/home/xxx/xxx
Environment="DJANGO_SETTINGS_MODULE=xxx.settings"
ExecStart=/home/django/xxx/venv/bin/gunicorn xxx.wsgi --bind 0.0.0.0:8000 --log-level error --log-file=- --workers 5 --preload --access-logfile /home/django/xx/logs/gunicorn/output.log --error-logfile /home/django/xx/logs/gunicorn/error.log
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
Restart=on-abort
PrivateTmp=true
#StandardOutput=append:/home/xxx/xxx/logs/gunicorn/output.log
#StandardError=append:/home/xxx/xxx/logs/gunicorn/error.log

[Install]
WantedBy=multi-user.target

daphne.service

[Unit]
Description=daphne daemon
After=network.target

[Service]
PIDFile=/run/daphne/pid
User=django
Group=www-data
WorkingDirectory=/home/django/xxx
Environment="DJANGO_SETTINGS_MODULE=xxx.settings"
ExecStart=/home/django/xxx/venv/bin/daphne --bind 0.0.0.0 --port 8443 --verbosity 3 --access-log /home/django/xx/logs/daphne/access.log xxx.asgi:application
#ExecStart=/home/django/xxx/venv/bin/daphne -e ssl:8443:privateKey=privkey.pem:certKey=fullchain.pem -v 3 --access-log /home/django/xx/logs/daphne/access.log xxx.asgi:application 
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
Restart=on-abort
PrivateTmp=true
StandardOutput=append:/home/django/xxx/logs/daphne/access.log
StandardError=append:/home/django/xxx/logs/daphne/error.log

[Install]
WantedBy=multi-user.target

In local the websocket works perfectly, if I subscribe for example to a model with "pk = 1" if it is updated I receive changes in production the websocket connects but then I don't receive anything when I update the signed model.

var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    var conn = new ReconnectingWebSocket(ws_scheme + '://'
        + window.location.host
        + '/ws/observer/azienda/?token=9e1058f3d0539b51ff7350ae6f0b096a6553b240', null, {
        debug: true,
        reconnectInterval: 3000
    });
    conn.onmessage = function (e) {
        console.log("connesso")
        console.log(e.data);
    };

    conn.onopen = () => conn.send(
        (JSON.stringify({
                "action": "subscribe_instance",
                'pk': 1,
                "request_id": 34,
            })
        ));
    conn.onclose = function (e) {
        console.log(e)
        console.error('Error websocket');
    };

Locally, I receive changes via websocket

connesso
(index):26 {"errors": [], "data": null, "action": "subscribe_instance", "response_status": 201, "request_id": 34}
(index):25 connesso
(index):26 {"errors": [], "data": {"id": 1}, "action": "update", "response_status": 200, "request_id": 34}

In production after the websocket connects I do not receive any updates if I modify for example the company with pk = 1

connesso
(index):26 {"errors": [], "data": null, "action": "subscribe_instance", "response_status": 201, "request_id": 34}

Log daphne prod:

127.0.0.1:55674 - - [31/Jul/2020:11:00:29] "WSCONNECTING /ws/observer/azienda/" - -
127.0.0.1:55674 - - [31/Jul/2020:11:00:29] "WSCONNECT /ws/observer/azienda/" - -

Log daphne local

WebSocket HANDSHAKING /ws/observer/azienda/ [172.27.0.1:60296]
WebSocket CONNECT /ws/observer/azienda/ [172.27.0.1:60296]

Final Solution for work gunicorn/daphne with nginx!

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

server {
    listen xxx.it:443 ssl http2;
    server_name xx.it www.xx.it;
    tcp_nodelay on;

    client_max_body_size 20M;
    access_log /var/log/nginx/xx.it.access.log;
    error_log /var/log/nginx/xx.it.com.error.log;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/django/xxx/;
        expires 1M;
        access_log off;
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_redirect off;
        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;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header Connection "";
        server_tokens off;
        proxy_buffering on;
        if (!-f $request_filename) {
          proxy_pass http://127.0.0.1:8443;
          break;
        }
    }

    location /ws {
         proxy_pass http://127.0.0.1:8443;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
         proxy_set_header Host $http_host;
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection "upgrade";
    }

    ssl_certificate /etc/letsencrypt/live/xxx.it/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/xx.it/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
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source