How to enable SSL support using Apache + Fastcgi + Django? - django

I have written a Django App and I want to enable SSL(Https) support in my deployment. Currently my web application is properly served on port80. This is my setup
I am using Apache as my web server
FastCGI as reverse proxy to serve my web app
I launch my Django app using the following command
/usr/bin/python manage.py runfcgi daemonize=false method=threaded host=127.0.0.1 port=8080
I edited the Apache httpd.conf file accordingly
<VirtualHost _default_:80>
Alias /static /opt/tms/web3/static
#For every request that *doesn't* start with "static", send it
#to Django via fastcgi. The address and port must match the
#arguments that are later passed to Django.
<LocationMatch "^/(?!static)">
ProxyPass fcgi://127.0.0.1:8080/
</LocationMatch>
</VirtualHost>
<VirtualHost _default_:443>
Alias /static /opt/tms/web3/static
#For every request that *doesn't* start with "static", send it
#to Django via fastcgi. The address and port must match the
#arguments that are later passed to Django.
<LocationMatch "^/(?!static)">
ProxyPass fcgi://127.0.0.1:8080/
</LocationMatch>
LogLevel warn
ErrorLog /var/log/web_error_log
LogFormat combined
CustomLog /var/log/web_access_log combined
SSLEngine on
SSLCertificateFile /var/opt/tms/web/conf/webserver.cert.pem
SSLCertificateKeyFile /var/opt/tms/web/conf/webserver.priv.pem
SSLCertificateChainFile /var/opt/tms/web/conf/webserver_chain.cert.pem
SSLOptions +StdEnvVars
SSLProtocol -all +TLSv1 +TLSv1.1 +TLSv1.2
SSLCipherSuite HIGH:-aNULL:-kKRB5:-MD5
FileETag None
</VirtualHost>
and I get this error when I access with https
Unable to make a secure connection to the server. This may be a problem with
the server, or it may be requiring a client authentication certificate that you don't have.
Error code: ERR_SSL_PROTOCOL_ERROR

Related

Apache WSGI vs. Django Development Server

I recently decided to deploy my Django project using Apache and mod_WSGI. So, whereas my dev server runs on localhost:8000, my "Apache WSGI" server runs on localhost.
Everything looked good until I tried to POST to my Django REST API. For whatever reason, I can post perfectly fine to the Django dev server, but I cannot post to the Apache WSGI server.
As a matter of fact, I do not even see that a POST attempt was logged when I look at my Apache logs--I can see url errors there (when I purposefully try to go to a page that doesn't exist for example) but no failed POST attempts. What can be causing this problem and how can I troubleshoot it?
Could it be that the Django REST Framework is incompatible with WSGI? I am puzzled why everything else: admin page, logins, navigation, update views, forms, etc, work perfectly fine but this one thing is not even showing up in the logs.
EDIT: This is my virtual host file:
<VirtualHost *:80>
# 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
ServerAdmin webmaster#localhost
DocumentRoot /var/www/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".
#Include conf-available/serve-cgi-bin.conf
Alias /static /home/pi/myapp/myapp2/myapp/static
<Directory /home/pi/myapp/myapp2/myapp/static>
Require all granted
</Directory>
<Directory /home/pi/myapp/myapp2/myapp/myapp>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIApplicationGroup %{GLOBAL}
WSGIDaemonProcess myapp python-path=/home/pi/myapp/myapp2/myapp python-home=/home/pi/WebApp/p3
WSGIProcessGroup myapp
WSGIScriptAlias / /home/pi/myapp/myapp2/myapp/myapp/wsgi.py
</VirtualHost>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Django Channels over apache server

I have a Django project that's working well on my VPS over apache.
after adding Django channels to my project it's working on localhost perfectly but in my vps, my browser logged an error "WebSocket connection to '...' failed: Error during WebSocket handshake: Unexpected response code: 404" and the project failed.
according to my googling, I think apache can't support web-socket. but can't find a clear answer and trip for running channels on apache
this is my apache config in 000-default.conf:
<VirtualHost *:80>
Alias /static /opt/kalameh/static
<Directory /opt/kalameh/static>
Require all granted
</Directory>
<Directory /opt/kalameh/server>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIDaemonProcess kalameh python-path=opt/kalameh python-home=opt/kalameh/kalamehenv
WSGIProcessGroup kalameh
WSGIScriptAlias / opt/kalameh/server/wsgi.py
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
and this is my wsgi.py
import os
import sys
sys.path.append('/opt/kalameh/')
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")
application = get_wsgi_application()
You need to check channels' Deploying section. Be aware the slight differences between channels v1.x and v.2x documentation. Pick up the appropriate one.
As you notice, Apache does not support websocket. So you would need to run a server that exposes websocket - a native ASGI interface server (terminology used by channel documentation). You can use Django's Daphne. Daphne also supports HTTP interface.
So you have two solutions:
Keep Apache delivering your Django's HTTP request + Daphne delivering your websocket (if you go for this solution, the keywords to use to find more documentation are reverse proxy and ProxyPass)
Using Daphne for delivering your Websocket and HTTP (no need of Apache).

Using Apache to proxy requests based on URL parameter

I have a back-end application (Django) that requires its static content (assets like images, scripts, stylesheets, etc.) to be served by a web server.
At current, I have my Django application serving on localhost:5000. I have this sitting behind an Apache2 server virtual host that is using mod_proxy to send requests to the Django app in the back.
I need to configure my VHost so that all of the URI requests for domain.com/static/asset will serve the asset from /path/to/asset statically, while everything else gets proxied to the back-end app localhost:5000.
My VHost config looks like this at the moment, the commented bits don't work properly.
<VirtualHost *:80>
ServerName www.domain.com
ServerAlias domain.com
ServerAdmin info#domain.com
ErrorLog ${APACHE_LOG_DIR}/domain_error.log
CustomLog ${APACHE_LOG_DIR}/domain_access.log combined
ProxyRequests Off
ProxyVia Off
<Proxy *>
Require all granted
</Proxy>
# DocumentRoot /path/to/static
# <Directory /path/to/static/>
# Require all granted
# </Directory>
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
</VirtualHost>

How to configure apache2 on ubuntu for django restful services

I have django restful services on my ubuntu server which are running on port 84.
When the request is send, it come through the apache2 server which is running on port 80.
Now let say my server ip is "xx.xx.xx.10" and when i call with this url http://xx.xx.xx.10/user where user is the rest service running on django rest framework on port 84. Then the request should go to my django rest service through apache2 and return the desired output.
I tried by using the below configuration in the apache2 :-
<VirtualHost *:80>
WSGIScriptAlias / /myproject/myapp/test/wsgi.py
<Directory "/myproject/myapp/test/">
<Files "wsgi.py">
Require all granted
</Files>
</Directory>
</VirtualHost>
but this is giving internal error saying that test.settings does not exits.
is this the right way to configure the restful services running on different port on apache server.
Did you specify a python path? If you don't, import mysite will not work.
WSGIPythonPath /path/to/mysite.com
For more info see: Django docs modWSGI
I have solved this issued by using the below configurations :-
<VirtualHost *:80>
ServerName mydomain
ServerAlias *.mydomain
ProxyRequests off
ProxyPass / http://localhost:84/
ProxyPassReverse / http://localhost:84/
</VirtualHost>

apache + django + mod_wsgi conversion to https keeps going back to http

I've had a django (satchmo) site using Apache and mod_wsgi running fine for a couple of years now. Until now it has only served http, and I'm trying to convert the entire site to https. I have a signed ssl certificate which I believe is fine.
I have adapted my Apache configuration according to my understanding of the docs.
When I try to connect to the site using https, the browser connects fine on port 443, and the Apache server responds with the correct ssl certificate followed by the TLS key exchange etc (according to what I see in Wire Shark). At that point everything looks fine and there are no errors. But..
Once the ssl connection is established, the browser then initiates a "GET / HTTP/1.1" in a new TCP connection to port 80 (i.e. http). It's like it knew nothing about the https connection already in place.
Is it possible that django is at fault? I have not changed the django configuration at all, as I was under the impression that only Apache needs to know about it? (I don't use nginx - Apache handles all of the content.)
I can't "see" what is going on in the ssl conversation, but presumably django is telling the browser client to connect on port 80 somehow? Is that possible?
To make things simple, I now have a plain index.html page when you connect to http, and I've moved all of the django & mod_wsgi to port 443. If I connect straight to the http address, I get the simple index page, no problem.
When I try to connect to the https address, the browser effectively gets redirected to the index.html page. (I don't have any Redirect or Rewrite commands in Apache though.)
Here is my Apache configuration:
<VirtualHost *:80>
ServerName demo.pasta.co.za
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
DocumentRoot /var/www/http_site
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM
SSLCertificateFile /etc/ssl/private/pasta.co.za.crt
SSLCertificateKeyFile /etc/ssl/private/pasta.co.za.key
SSLCertificateChainFile /etc/ssl/private/root_bundle.crt
ServerName demo.pasta.co.za
Alias /favicon.ico /usr/local/django/pasta/static/favicon.ico
Alias /robots.txt /usr/local/django/pasta/static/robots.txt
AliasMatch ^/([^/]*\.css) /usr/local/django/pasta/store/static/$1
WSGIDaemonProcess demo.pasta.co.za processes=2 threads=25 display-name=%{GROUP}
WSGIProcessGroup demo.pasta.co.za
WSGIScriptAlias / /usr/local/django/pasta/apache/django.wsgi
<Directory /usr/local/django/pasta/apache>
Order allow,deny
Allow from all
</Directory>
Alias /static/admin/ /usr/share/pyshared/django/contrib/admin/static/admin/
Alias /static/images/ /usr/local/django/pasta/store/static/images/
Alias /static/ /usr/local/django/pasta/store/static/
Alias /media/ /usr/local/django/pasta/store/static/
<Directory /usr/local/django/pasta/store/static>
Order deny,allow
Options -Indexes
Allow from all
</Directory>
<Directory /usr/share/pyshared/django/contrib/admin/static/admin>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
And here is my mod_wsgi file:
import os, sys
sys.path.insert (0,"/usr/local/django/pasta/store")
import settings
import django.core.management
django.core.management.setup_environ(settings)
utility = django.core.management.ManagementUtility()
command = utility.fetch_command('runserver')
command.validate()
import django.conf
import django.utils
django.utils.translation.activate(django.conf.settings.LANGUAGE_CODE)
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
There are dozens of examples on SO where people accomplish what I'm trying to do with more or less what I have above.
What am I missing? It feels like I've left out something really obvious.
I have Debian stable running django v1.4.5 python v2.7.3 and apache v2.2.22 with mod-wsgi v3.3-4.
Many thanks!
Accepted answer for satchmo nginx redirect to https then to http and back by mipadi ...
Satchmo includes a piece of middleware called satchmo_store.shop.SSLMiddleware.SSLRedirect, which automatically does redirecting to SSL/non-SSL portions of the site. You have to set up URLs to be served via SSL if you want them to be served via SSL, otherwise the middleware redirects to a non-SSL page. From the docs:
This middleware answers the problem of redirecting to (and from) a SSL secured path by stating what paths should be secured in urls.py file. To secure a path, add the additional view_kwarg 'SSL':True to the view_kwargs.
For example
urlpatterns = patterns('some_site.some_app.views',
(r'^test/secure/$','test_secure',{'SSL':True}),
)
All paths where 'SSL':False or where the kwarg of 'SSL' is not specified are routed to an unsecure path.
For example
urlpatterns = patterns('some_site.some_app.views',
(r'^test/unsecure1/$','test_unsecure',{'SSL':False}),
(r'^test/unsecure2/$','test_unsecure'),
)
In your case, since you're serving the entire site via SSL, you can probably just disable that middleware in your settings.py file.
(From my experiance you need to change quite a few urlpatterns in a few files.)