How to deploy django channels with Apache and Daphne? - django

I am trying to deploy this django app which uses channels. I use Apache for regular HTTP requests and want to forward the web socket requests to Daphne.
Here are some of my important files:
apache config:
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
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/anna/tchan/static
<Directory /home/anna/tchan/static>
Require all granted
</Directory>
Alias /media /home/anna/tchan/media
<Directory /home/anna/tchan/media>
Require all granted
</Directory>
<Directory /home/anna/tchan/tchan>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIScriptAlias / /home/anna/tchan/tchan/wsgi.py
WSGIDaemonProcess django_app python-path=/home/anna/tchan python-home=/home/anna/tchan/venv
WSGIProcessGroup django_app
</VirtualHost>
Last few lines of settings.py:
ASGI_APPLICATION = 'tchan.routing.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 8001)],
},
},
}
asgi.py
import os
import django
from channels.routing import get_default_application
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tchan.settings')
django.setup()
application = get_default_application()
With these in place, I run daphne -p 8001 tchan.asgi:application and then sudo service apache2 reload.
Finally, when testing the websocket in my page here's what happens:
websocket.js:4 WebSocket connection to 'ws://192.168.0.57/ws/chat/8/' failed: Error during WebSocket handshake: Unexpected response code: 403
This error 403 happens whether or not I'm running daphne.
What am I doing wrong here?
Note: the app works as expected when using Django's development server and docker for the channel layer, the problem is with my Apache config, I think.

I figured it out. To enable apache to redirect, we need to:
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
One of these was not enabled which caused the 403 Forbidden.

Related

Django apache wsgi returns Error 403 Forbidden

I want to have a base authentication into my django application by apache's base auth.
my config looks like this:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName url.test.com
ServerAdmin webmaster#localhost.com
ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/
WSGIDaemonProcess projectname \
python-home=/home/user/app/project/env \
python-path=/home/user/app/project:/home/user/app/project/env/lib/python3.5/site-packages/
WSGIProcessGroup projectname
WSGIScriptAlias / /home/user/app/project/app/server/wsgi.py
WSGIPassAuthorization On
Alias /static/ /home/user/app/app/project/static/
ErrorLog ${APACHE_LOG_DIR}/error-log
CustomLog ${APACHE_LOG_DIR}/access-log combined
LogLevel info
# Protecting with basic authentication
<Location />
AuthType Basic
AuthName "Restricted Content"
AuthUserFile /etc/apache2/.htpasswd
Require user testuser
AuthBasicProvider wsgi
WSGIAuthUserScript /home/user/app/project/app/server/wsgi.py
</Location>
SSLCertificateFile /etc/letsencrypt/live/project.app.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/project.app.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
and wsgi.py containing:
import os
import sys
sys.path.insert(0, '/home/user/app/project')
sys.path.append('/home/user/app/project/env/lib/python3.5/site-packages')
os.environ["DJANGO_SETTINGS_MODULE"] = "project.app.settings"
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
with this setup I get the error message:
AH01618: user testuser not found: /
after some research I've seen that I probably should remove AuthBasicProvider and WSGIAuthUserScript from Location to:
# Protecting with basic authentication
<Location />
AuthType Basic
AuthName "Restricted Content"
AuthUserFile /etc/apache2/.htpasswd
Require user testuser
</Location>
this leads to the password being accepted, but then I get a 403 error in the django application:
Forbidden: /
[11/Mar/2020 17:23:35] "GET / HTTP/1.1" 403 13
as I'm usually more on the coding side I'm not super familiar with the setup of the django application behind apache and struggling. Anyone sees my problem?

Deploy django-channels with Apache2 and Daphne

I'm trying to learn to use django-channels and have worked through both the tutorial and this multichat example. I am now trying to deploy it on a Digital Ocean droplet using Apache and Daphne. I would happily use Daphne by itself but I do not understand how to.
So this is my Apache conf file:
<VirtualHost *:80>
ServerAdmin webmaster#mysite.co.uk
ServerName multichat.mysite.co.uk
ServerAlias www.multichat.mysite.co.uk
DocumentRoot /var/www/multichat
WSGIDaemonProcess multichat python-path=/var/www/multichat python-home=/var/www/multichat/env
WSGIProcessGroup multichat
WSGIScriptAlias / /var/www/multichat/multichat/wsgi.py
Alias /robots.txt /var/www/multichat/static/robots.txt
Alias /favicon.ico /var/www/multichat/static/favicon.ico
Alias /media/ /var/www/multichat/media/
Alias /static/ /var/www/multichat/static/
<Directory /var/www/multichat/static>
Require all granted
</Directory>
<Directory /var/www/multichat/media>
Require all granted
</Directory>
WSGIScriptAlias / /var/www/multichat/multichat/wsgi.py
<Directory /var/www/multichat/multichat>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
I've installed Redis and have it up and running.
I've included this file in /etc/systemd/system/daphne.service
[Unit]
Description=daphne daemon for multichat
After=network.target
[Service]
User=root
Group=www-data
WorkingDirectory=/var/www/multichat/multichat
ExecStart=/var/www/multichat/env/bin/daphne -b 0.0.0.0 -p 8001 multichat.asgi:application
# Not sure if should use 'on-failure' or 'always'.
Restart=on-failure
[Install]
WantedBy=multi-user.target
Although the webpage comes up and I can login etc, when it comes to a chatroom I have the following error in console:
WebSocket connection to 'ws://multichat.mysite.co.uk/chat/stream/'
failed: Error during WebSocket handshake: Unexpected response code:
404
I'm clearly not setting up something correctly but I don't know where to turn. I would happily scrape Apache if I can get a pointer on how to use just Daphne, but I've tried and got nowhere with that either
You've configured Apache to serve Django content using WSGI protocol, but WSGI doesn't support web sockets. That is why Daphne is here. It doesn't use WSGI to serve Django content, so you can use it with web sockets.
To use Daphne instead, you should remove WSGI settings from apache file and put ProxyPass instead, which should point to your daphne server. The proper line should look like this:
<Location />
ProxyPass http://127.0.0.1:8001/
</Location>
As your daphne server is running on the same server, but on port 8001.
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]
<Location />
ProxyPass http://127.0.0.1:8001/
</Location>
#And load the next modules in the main file config:
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_module modules/mod_proxy.so
#remove WSGI settings

Django Channels wss not connecting received 404 Error

I am attempting to move my server off my local subnet and to a domain. The main webpages are working and I have them behind an SSL. Apache does a rewrite of the url from any HTTP connection to an HTTPS. However when I attempt to connect with javascript from in browser with:
new WebSocket("wss://" + window.location.host);
I receive the following error:
WebSocket connection to 'wss://{MY_WEBSITE}.com/message_route/' failed: Error during WebSocket handshake: Unexpected response code: 404
My config for the settings.py is as follows:
"default": {
"BACKEND": "asgi_redis.RedisChannelLayer",
"ROUTING": "my_app.routing.channel_routing",
"Config": {
"hosts": [os.environ.get('REDIS_URL', 'redis://127.0.0.0:6379')],
}
},
EDIT (ADDED IN APACHE CONFIG DATA):
My Apache default.conf is the following (simple re-write to HTTPS):
<VirtualHost *:80>
RewriteEngine on
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
</VirtualHost>
Apache secure.conf:
<VirtualHost *:443>
ServerName my_domain.com
SSLEngine on
SSLProxyEngine on
SSLCertificateFile /etc/ssl/my_domain/my_domain.crt
SSLCertificateKeyFile /etc/ssl/my_domain/myserver.key
SSLCACertificateFile /etc/ssl/my_domain/my_domain.ca-bundle
Alias /static /home/user/my_app/myApp/static_files
<Directory /home/user/my_app/myApp/static_files>
Require all granted
</Directory>
<Directory /home/user/my_app/myApp/MyApp>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIDaemonProcess MyApp python-path=/home/user/my_app/myApp/MyApp
WSGIProcessGroup MyApp
WSGIScriptAlias / /home/user/my_app/myApp/MyApp/MyApp/wsgi.py
</VirtualHost>
EDIT Found out apache is receiving request but not doing anything
I tailed other_vhosts.access.log and found that when I created a new websocket in chromes console, apache logs that a GET request, but does not seem to forward it to my django app.
I also have a worker running, a redis server set up, and daphne running as well. Please let me know if you can think of any possible solutions to this problem

Why POST requests are turned into GET in django with wsgi?

I have a Django 1.9.4 site.
In localhost, I could easily submit the form and have the results that I want.
But when it's on the server, the POST request turns into a GET request.
On local, I use python manage.py runserver but on server I use Apache2, WSGI
Local:
django 1.9.4
python 2.7.10
Ubuntu 15.10
Server:
same django
python 2.7.6
Server version: Apache/2.4.7 (Ubuntu)
Ubuntu 14.04
Server example.com.conf:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
ServerAdmin email#gmail.com
Alias /static /var/www/example.com/static
<Directory /var/www/example.com/static>
Require all granted
</Directory>
Alias /media /var/www/example.com/media
<Directory /var/www/example.com/media>
Require all granted
</Directory>
<Directory /var/www/example.com/wh>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIDaemonProcess webhistory python-path=/var/www/example.com:/var/www/example.com/env/lib/python2.7/site-packages
WSGIProcessGroup webhistory
WSGIScriptAlias / /var/www/example.com/wh/wsgi.py
ErrorLog /var/www/example.com/logs/error.log
CustomLog /var/www/example.com/logs/access.log combined
Alias /robots.txt /var/www/example.com/robots.txt
Alias /favicon.ico /var/www/example.com/favicon.ico
</VirtualHost>
And the wsgi.py:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wh.settings")
application = get_wsgi_application()
And the craziest part is that even my admin app doesn't work properly.
All the POST submitted forms turn into GET ones.
Here is the error:
request <WSGIRequest: GET '/someurl/'>
What's the problem?
Is it related to APPEND_SLASH = True?
And here's what's realley bothering me... The form submission worked once! why isn't it working again?

No module named registro.forms in my own local django server [edited]

im setting Django Server in my Ubuntu machine, apache/wsgi, but im getting a error in my view:
was No module named registro.forms now after some code in my wsgi is No module name forms
#registro.views
from registro.forms import ComercioForm
In my laptop is running but not in my server machine
django is running
all database table are syncd
WSGI
#path /srv/www/project/apache/django.wsgi
import is, sys
sys.path.insert(0,'/srv/www')
sys.path.insert(0,'/srv/www/project')
sys.path.insert(0,'/srv/www/') #testing
sys.path.insert(0,'/srv/www/project/') #testing
os.environ['DJANGO_SETTINGS_MODULE']='project.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
httpd.conf
#path /srv/www/project/apache/
Alias /media/ "/srv/www/project/public/admin_tools"
<Directory "/srv/www/project/public/admin_tools">
Allow from all
</Directory>
WSGIScriptAlias "/srv/www/project/apache/django.wsgi"
<Directory "/srv/www/project/apache">
Allow from all
</Directory>
project
#path /etc/apache2/sites-available
<VirtualHost *:80>
ServerName project
DocumentRoot /srv/www/project
<Directory /srv/www/project>
Order allow,deny
Allow from all
</Directory>
WSGIDeamonProcess project processes=2 threads=15 display-name=%{GROUP}
WSGIProcessGroup project
WSGIScriptAlias / /srv/www/project/apache/django.wsgi
</VirtualHost>
Any idea?
thanks
You probably don't have the "registro"-application in your Django-Path. For an example how to fix it, see here
.