django channels deploy

Easily Deploy Django Channels by configuring Nginx to run both Gunicorn and Daphne

Django Channels enables a developer to use WebSockets and other non-HTTP protocols in any Django project. By, using non-HTTP protocol the website can receive real-time updates from the server. The most common use case for Django Channels would be when we want to implement a chat application. Chat applications need to be real-time and seamless and that is where Django channels offer great benefits over using traditional Ajax-based request-response chat models. Unfortunately, new developers might find Django channels both hard to implement and difficult to deploy. Luckily, its official documentation covers a great tutorial on implementation which I will be linking below. Django channels require ASGI (Asynchronous Server Gateway Interface) for deployment. We will be using Daphne for ASGI. WSGI (Web Server Gateway Interface) will be used for the rest of the project deployment. For WSGI, Gunicorn will be used. The tutorial is of an intermediate level and some prerequisite tutorial needs to be followed beforehand.

Prerequisite Tutorials

  1. Simple Add Object functionality in Django for showcasing usage of WSGI
  2. Setting up the server for Django WSGI Deployment with Nginx, Gunicorn (Section A only. Modify it to host prerequisite 1)
  3. Official Django Channel Tutorial for showcasing usage of ASGI (Part 1 & 2 only)

Deployment of both WSGI and ASGI using Nginx and Supervisor

This tutorial mostly follows the official documentation with some modifications.

Replace the projects asgi.py file content with this:

import os
from django.conf.urls import url

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_examples.settings')

from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
django_asgi_app = get_asgi_application()

from channels.auth import AuthMiddlewareStack   
import chat.routing


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

Since, Nginx should be already installed in first prerequisite we only need to install Supervisor.

$ sudo apt install supervisor

Let us now make a config file called channels.conf inside /etc/supervisor/conf.d/ -The supervisor will listen on a TCP port and then pass the socket to the child process for further processing. The file will contain this :

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

# Directory where your site's project files are located
directory=/home/saif/django_examples

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

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

# 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=/var/log/asgi.log
redirect_stderr=true

Create the run directory for the sockets referenced in the supervisor configuration file.

$ sudo mkdir /run/daphne/

If the supervisor fcgi-program is being run under a different user make sure to change the owner settings of the run directory.

$ sudo chown <user>.<group> /run/daphne/

On every server reboot, the /run/daphne folder will be cleared out. To make it persistent create a file /usr/lib/tmpfiles.d/daphne.conf and add the following in its content:

$ d /run/daphne 0755 <user> <group>

Make sure the supervisor reread and update itself with the new job:

$ sudo supervisorctl reread
$ sudo supervisorctl update

Next, put the following setting in your Nginx Config file:

upstream ws_server {
    server localhost:8000;
}


server {
    listen 80;
    server_name 'mywebsite.com';

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/saif/django_examples;
    }
 # WSGI
    location / {
        try_files $uri @proxy_to_app;
    }
# ASGI
    location /ws {
        try_files $uri @proxy_to_ws;
    }

    location @proxy_to_ws {
        proxy_pass http://ws_server;
        
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

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

    location @proxy_to_app {
        include proxy_params;
        proxy_pass   http://unix:/home/saif/django_examples/django_examples.sock;
    }

}

Reload Nginx to apply the new changes:

$ sudo service nginx reload

That’s it. Your server should be able to serve both ASGI and WSGI based apps now. In case you faced some issue. I have followed the official Django Channels tutorial and updated the code in my Github repository. The tutorial is followed in the chat app. Simply download and deploy it in your local machine.

close

FREE ARTICLES

Hey! If you want to receive more free articles in your Inbox. SUBSCRIBE NOW!!

Leave a Reply

Your email address will not be published. Required fields are marked *