Deploy Django + Channels website with nginx and daphne server on ubuntu
![Django + Channels deployment](/assets/blog/django-channels.webp)
Deploy Django + Channels website with nginx and daphne server on ubuntu
Get all files here Github repo.
Specifications
- Ubuntu 20.04
- Django Channels 3
- Redis Install and Config
- ASGI for Hosting Django Channels
- Deploying Django Channels with Daphne using supervisor
- Starting the daphne service
- Writing a supervisor script that tells daphne to start
- Configure Nginx
- HTTPS with letsencrypt
basic apt reuired
sudo apt-get update && sudo apt-get upgrade -y
sudo apt install python3.9 -y
sudo apt-get install python3.9-dev python3.9-venv -y
sudo apt-get install python3-pip -y
sudo apt install nginx supervisor
requirement.txt
django
channels
channels_redis
Start Django project in virtual env
cd ~
mkdir venv
python3.9 -m venv ~/venv/.
source ~/venv/bin/activate
pip install setproctitle
pip install -r ~/requirements.txt
django-admin.py startproject PROJECT-NAME
cd ~/PROJECT-NAME
mkdir media static templates
python manage.py startapp home
python manage.py migrate
sudo adduser $USER www-data
sudo chown -R :www-data ~/PROJECT-NAME/
sudo chown :www-data ~/PROJECT-NAME/db.sqlite3
sudo chmod -R 775 ~/venv/
sudo chmod -R 775 ~/PROJECT-NAME/
Install and Setup Redis
Redis is used as a kind of "messaging queue" for django channels. Read more about it here channel_layers
sudo apt install redis-server
Navigate to /etc/redis/
open redis.conf
CTRL+F
to find 'supervised no'
change 'supervised no' to 'supervised systemd'
SAVE
sudo systemctl restart redis.service
sudo systemctl status redis
Add "CHANNEL_LAYERS" & "ASGI_APPLICATION" to installed app in settings
ASGI_APPLICATION = "PROJECT-FOLDER.asgi.application"
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("redis-server-name", 6379)],
},
},
}
Edit asgi.py
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "PROJECT-FOLDER.settings")
django_asgi_app = get_asgi_application()
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.urls import path
from chat.consumers import ChatConsumer
application = ProtocolTypeRouter(
{
"http": django_asgi_app,
"websocket": AuthMiddlewareStack(
URLRouter(
[
path("", ChatConsumer.as_asgi()),
]
)
),
}
)
Deploying Django Channels with Daphne Ref
Now, you will need to create the supervisor configuration file (often located in /etc/supervisor/conf.d/ - here, we’re making Supervisor listen on the TCP port and then handing that socket off to the child processes so they can all share the same bound port:
supervior.conf
[fcgi-program:asgi]
socket=tcp://localhost:8001
directory=/home/ubuntu/PROJECT-FOLDER
command=/home/ubuntu/venv/bin/daphne -u /home/ubuntu/PROJECT-FOLDER/run/daphne%(process_num)d.sock --fd 0 --access-log - --proxy-headers PROJECT-FOLDER.asgi:application
numprocs=4
process_name=asgi%(process_num)d
autostart=true
autorestart=true
stdout_logfile=/home/ubuntu/logs/daphne-error.log
redirect_stderr=true
Create the run directory for the sockets referenced in the supervisor configuration file.
sudo mkdir /home/ubuntu/PROJECT-FOLDER/run/
sudo mkdir /home/ubuntu/logs/
sudo chown <user>.<group> /home/ubuntu/PROJECT-FOLDER/run/
sudo chmod -R 775 ~/PROJECT-FOLDER/
Have supervisor reread and update its jobs:
sudo supervisorctl reread
sudo supervisorctl update
Configure Nginx
We need to tell nginx to allow websocket data to move through port 8001.
Navigate to /etc/nginx/sites-available
Update default
file
upstream daphne_server {
server localhost:8001;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name <DOMAIN>;
keepalive_timeout 5;
client_max_body_size 4G;
access_log /home/ubuntu/logs/nginx-access.log;
error_log /home/ubuntu/logs/nginx-error.log;
location /static/ {
alias /home/ubuntu/PROJECT-FOLDER/static/;
}
location /media/ {
alias /home/ubuntu/PROJECT-FOLDER/media/;
}
location / {
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
proxy_pass http://daphne_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;
}
}
HTTPS (If you have a domain registered and it's working)
Do not do this step unless you're able to visit your website using the custom domain. See How do you know it's working?
Install certbot
HTTPS is a little more difficult to set up when using Django Channels. Nginx and Daphne require some extra configuring.
sudo apt install certbot python3-certbot-nginx
sudo systemctl reload nginx
Make sure nginx configuration is still good.
sudo nginx -t
Allow HTTPS through firewall
sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'
Block standard HTTP
Obtain SSL certificate
sudo certbot --nginx -d <your-domain.whatever> -d www.<your-domain.whatever>
For eg:
sudo certbot --nginx -d demo.xyz -d www.demo.xyz
Verifying Certbot Auto-Renewal
sudo systemctl status certbot.timer
Test renewal process
sudo certbot renew --dry-run
Update nginx config
Navigate to /etc/nginx/sites-available
Update default
file for the cert
upstream daphne_server {
server localhost:8001;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl; # managed by Certbot
server_name <DOMAIN>;
# RSA certificate
ssl_certificate /etc/letsencrypt/live/<DOMAIN>/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/<DOMAIN>/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
Redirect non-https traffic to https
if ($scheme != "https") {
return 301 https://$host$request_uri;
} # managed by Certbot
keepalive_timeout 5;
client_max_body_size 4G;
access_log /home/ubuntu/logs/nginx-access.log;
error_log /home/ubuntu/logs/nginx-error.log;
location /static/ {
alias /home/ubuntu/PROJECT-FOLDER/static/;
}
location /media/ {
alias /home/ubuntu/PROJECT-FOLDER/media/;
}
location / {
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
proxy_pass http://daphne_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;
}
}
Check and restart nginx and daphne server
sudo supervisorctl restart asgi
sudo supervisorctl status
sudo nginx -t && sudo systemctl restart nginx