I have been playing around with django channels and everything seemed to be working in my development environment, but now I am having trouble deploying it to my local server.
I am aware there have been similar questions on this topic and I have tried my best to solve this using them, but have had no luck.
Im using apache2 to serve the application, and trying to redirect any websocket requests daphne. The web page loads without problem, but in the browser console I get the error
(webbSocket connection to 'wss://MYDOMAIN/ws/main/' failed:)
Here us my apache conf
<VirtualHost *:444>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerName myDomain
ServerAdmin admin
DocumentRoot /var/www/thomasmichaelides/public_html
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
# Enable Websocket connections on port 8888
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC,OR]
RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
RewriteRule .* ws://127.0.0.1:8001%{REQUEST_URI} [P,QSA,L]
Alias /static /home/atwebapps/arduinoDjango/static
<Directory /home/atwebapps/arduinoDjango/static>
Require all granted
</Directory>
<Directory /home/atwebapps/arduinoDjango/arduinoDjango>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIScriptAlias / /home/atwebapps/arduinoDjango/arduinoDjango/wsgi.py
WSGIDaemonProcess arduinoApp python-path=/home/atwebapps/arduinoDjango python-home=/home/atwebapps/arduinoDjango/venv
WSGIProcessGroup arduinoApp
SSLCertificateFile /etc/letsencrypt/live/mydomain/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/mydomain/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
and here is my daphne.service
[Unit]
Description=WebSocket Daphne Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/home/atwebapps/arduinoDjango
ExecStart=/home/atwebapps/arduinoDjango/venv/bin/python /home/atwebapps/arduinoDjango/venv/bin/daphne -b 0.0.0.0 -p 8001 arduinoDjango.asgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.target
Is there anything obvious as to why the ws connection keeps failing?
I will also put my asgi.py file as well as my settings.py
asgi.py
"""
ASGI config for arduinoDjango project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'arduinoDjango.settings')
application = get_asgi_application()
settings.py (channels related stuff)
INSTALLED_APPS = [
'main.apps.MainConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'channels',
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
WSGI_APPLICATION = 'arduinoDjango.wsgi.application'
ASGI_APPLICATION = 'arduinoDjango.routing.application'
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("localhost", 6379)],
},
},
}
use_websockets = True
Any insight to this would be greatly appreciated
You're close, but remember that the daphne service on the server is running multiple instances or python applications asynchronously. It works between the apache code and the django server code to redirect web traffic where it needs to go.
Therefore, you do not need to specify WSGIScriptAlias
WSGIDaemonProcess
or WSGIProcessGroup
. You need to specify what ports we are redirecting traffic to. You seem to have handled the http
traffic; but the trick with websockets here is that you have to remember that our browser must connect over the internet using wss
in contrast to the websocket which is actually running locally to our server. We can solve this issue by redirecting all wss
web traffic to the local port on ws
where the websocket is running.
Consider the following Apache conf with SSL which is required at production level.
...
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC,OR]
RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
RewriteRule .* ws://127.0.0.1:8001%{REQUEST_URI} [P,QSA,L]
ProxyPass /wss/ wss://127.0.0.1:8001/
ProxyPassReverse /wss/ wss://127.0.0.1:8001/
...
SSLEngine on
SSLCertificateFile /etc/ssl/certificate.crt
SSLCertificateKeyFile /etc/ssl/private/private.key
SSLCertificateChainFile /etc/ssl/ca_bundle.crt
...
Then you have to start the server, and so at production level you are going to need a Docker container or some methodology to keep the code running. Make sure to modify the port in production level to match your apache conf.
daphne -b 0.0.0.0 -p 8001 django_project.asgi:application // Local Development Level
daphne -e ssl:443:privateKey=key.pem:certKey=crt.pem django_project.asgi:application // Production Level