In one of my earlier post, we have seen an overview of how Django Channels work and how it helps us build cool stuff. However, in that post, we covered deployment briefly. So here in this post, we shall go over deployment again, with a little more details and of course code samples.
What do we need?
For running Django Channels, we would use the following setup:
- nginx as the proxy
- daphne as the interface server
- redis as the backend
Let’s get started.
Setup Redis and Configure App
We need to setup redis if it’s not installed already. Here’s how to do it on Ubuntu:
sudo apt-get install redis-server
If we want to use the redis backend, we also need to setup asgi-redis
.
pip install asgi_redis
In your settings.py
file, make sure you used redis as the backend and input the host properly.
Here’s a demo:
CHANNEL_LAYERS = {
"default": {
"BACKEND": "asgi_redis.RedisChannelLayer",
"CONFIG": {
"hosts": [("localhost", 6379)],
},
"ROUTING": "realtime.routing.channel_routing",
},
}
Starting Daphne
If you have installed channels
from pip, you should have the daphne
command available already. In the very
unlikely case you don’t have it installed, here’s the command:
pip install daphne
To run daphne, we use the following command:
daphne -b 0.0.0.0 -p 8001 <app>.asgi:channel_layer
Daphne will bind to 0.0.0.0
and use 8001
as the port.
Here <app>
is our app name / the module that contains the asgi.py
file. Please refer to the previous blog post
to know what we put in the asgi.py
file.
We now need to make sure daphne
is automatically started at system launch and restarted when it crashes. In this
example, I would stick to my old upstart script. But you would probably want to explore excellent projects like
circus
or supervisor
or at least systemd
.
Here’s the upstart script I use:
start on runlevel [2345]
stop on runlevel [016]
respawn
script
cd /home/ubuntu/<app home>
export DJANGO_SETTINGS_MODULE="<app>.production_settings"
exec daphne -b 0.0.0.0 -p 8001 <app>.asgi:channel_layer
end script
Running Workers
We need at least one running worker before daphne can start processing requests. To run a worker, we use the following command:
python manage.py runworker
The runworker
command spawns one worker with one thread. We should have more than one ideally. It is recommended
to have n
number of workers where n
is the number of available cpu cores.
Here’s a simple upstart script to keep the worker running:
start on runlevel [2345]
stop on runlevel [016]
respawn
script
cd /home/ubuntu/<app home>
export DJANGO_SETTINGS_MODULE="<app>.production_settings"
exec python3 manage.py runworker
end script
It would be much easier to launch multiple workers if you use supervisord or circus.
Nginx Conf
Finally here’s the nginx conf I use. Please note I handle all incoming requests with daphne which is probably
not ideal. You can keep using uwsgi
for your existing, non real time parts and only handle the real time part
with daphne. Since setting up wsgi is popular knowledge, I will just focus on what we need for daphne.
server {
listen 80;
client_max_body_size 20M;
location /static {
alias /home/ubuntu/<app home>/static;
}
location /media {
alias /home/ubuntu/<app home>/media;
}
location / {
proxy_pass http://0.0.0.0:8001;
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;
}
}
We have our daphne server running on port 8001
so we set a proxy to that url. Now if daphne and worker are
running, we should be able to see our webpage when we visit the url.