Debugging Apache/Django/WSGI Bad Request (400) Error - python

My simple Django app worked fine in debug mode (manage.py runserver), and works under WSGI+Apache on my dev box, but when I pushed to EC2 I began receiving intermittent (10-80% of the time) errors of Bad Request (400) for any URLs I try to view (whether in my app or in the Django admin.
Where can I find debug information about this? Nothing appears in /var/log/apache2/error.log, even with LogLevel=info. I have checked versions, logged the Request environment (cf. ModWSGI Debugging Tips) and see no major differences.
The one remaining thought I had is, I'm using the mod_wsgi from Ubuntu 12.04 (libapache2-mod-wsgi 3.3-4build1) which was built against Python 2.7.1; I have Python 2.7.3. And Django is 1.6, which is newer than the Ubuntu Precise version. I hesitate to start building packages from source since it's so hard to clean up and these seem like minor version changes...
Thank you for your help.
(For reference, here are the Apache config and WSGI apps)
Apache config (000-default)
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /var/www
WSGIScriptAlias /rz /usr/local/share/rz/rz.wsgi
...
rz.WSGI app
import os
import sys
import django.core.handlers.wsgi
import pprint
path = '/usr/local/share/rz'
if path not in sys.path:
sys.path.insert(0, path)
os.environ['DJANGO_SETTINGS_MODULE'] = 'rz.settings'
class LoggingMiddleware:
def __init__(self, application):
self.__application = application
def __call__(self, environ, start_response):
errors = environ['wsgi.errors']
pprint.pprint(('REQUEST', environ), stream=errors)
def _start_response(status, headers, *args):
pprint.pprint(('RESPONSE', status, headers), stream=errors)
return start_response(status, headers, *args)
return self.__application(environ, _start_response)
application = LoggingMiddleware(django.core.handlers.wsgi.WSGIHandler())

Add the ALLOWED_HOSTS setting to your settings.py like so...
ALLOWED_HOSTS = [
'.example.com', # Allow domain and subdomains
'.example.com.', # Also allow FQDN and subdomains
]
I had this same problem and found the answer here in the docs
update: django 1.6 docs are no longer online, I updated the link to go to the django 1.7 docs for ALLOWED_HOSTS setting.

If you've definitely set ALOWED_HOSTS - make sure your hostname doesn't contain underscores. It's technically illegal.
I had to print out various functions and it boiled down to this regex failing to detect a domain in django.http
host_validation_re = re.compile(r"^([a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9:]+\])(:\d+)?$")
And indeed, my domain had an underscore in it.

This is not a solution, but for debugging purposes you might set the ALLOWED_HOSTS setting in your settings.py like this
ALLOWED_HOSTS = ['*']
It should definitely work. If not, at least you will know the problem isn't Django denying access to the given url.

Related

Allow urls containing "www." on openshift hosted website

I have a (very) simple flask app hosted on open-shift.
It has one route:
#app.route('/')
def display_content():
return render_template("content.html.jnj2")
and a simple wsgi file (as described in the open-shift flask setup tutorial):
from wsgiref.simple_server import make_server
httpd = make_server('localhost', 8051, application)
httpd.serve_forever()
This works fine when I navigate to "myappname-mydomain.rhcloud.com", but gives an "ERR_NAME_NOT_RESOLVED" when I navigate to "www.myappname-mydomain.rhcloud.com".
I've done some googling etc, can't see anyone else with a similar problem.. I'm not aware of having changed any open-shift settings or anything.
Your app-domain.rhcloud.com address that is provided by OpenShift does NOT include a cname for www.app-domain.rhcloud.com, that's why it's not working. You can use your app-domain.rhcloud.com, or you can map your own alias like example.com or www.example.com using this guide: https://developers.openshift.com/en/managing-domains-ssl.html#using-a-custom-domain

How to get apache to serve static files on Flask webapp

I'm getting a 500 internal error while trying to get Apache to serve my static files.
The application will be locally hosted (not www facing). There will be no DNS to resolve a 'www.domain.com' name. I want to be able to access the application by entering the IP address of the server when I'm on that network.
This is my httpd.conf file (I'm on RHEL):
<Directory /var/www/testapp>
Order allow,deny
Allow from all
</Directory>
WSGIScriptAlias / /var/www/testapp/service.wsgi
If I change the WSGIScriptAlias to WGSIScriptAlias /test /var/www/testapp/service.wsgi then I can view my static files when I type in the IP, but I still can't access the service.py script from [IP]/test.
In any case, I want to be able to service all GET/POST requests with the service.py script so I want my alias to start at /, not some other place.
All my static files are in /var/www/html (Apache was automatically displaying these files before I messed with the httpd.conf, now I'm just getting a 500).
This is my service.wsgi:
import sys
sys.path.insert(0, '/var/www/testapp')
from service import app as application
This is my service.py:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello(environ, start_response):
status = '200 OK'
output = "Hello"
response_headers = [('Content-type', 'text/plain'), ('Content-length', str(len(output)))]
start_response(status, response_headers)
return output
if __name__=='__main__'
app.run()
Do I need keep my .wsgi files in the /var/www/html directory as well? Or can they go in a different folder? I can see that there might be some conflict between the message I am sending to the server ('Hello') and the static files that are already in the /var/www/html/ directory. That's why I tried setting the alias to /test but that didn't work either.
I just want my Flask application to service GET/POST requests and want apache to serve all the static files.
Fixing the 500 errors
You are currently getting 500 errors because your handler is a basic WSGI handler, but Flask handlers are not WSGI handlers (Flask / Werkzeug abstracts all that for you). Change your handler to:
#app.route("/")
def hello():
return "Hello"
and the 500 errors should go away.
Serving static files with Apache
The following techniques can be used when your application is serving the root of the domain (/), depending on whether you are using WSGIScriptAlias or AddHandler.
When using WSGIScriptAlias
When using the WSGIScriptAlias to mount a WSGI application at / you can use an Apache Alias directive to ensure that certain sub-routes are not handled by WSGIScriptAlias (this is further documented in mod_wsgi's wiki as well):
Alias "/static/" "/path/to/app/static/"
<Directory "/path/to/app/static/">
Order allow,deny
Allow from all
</Directory>
If you also want to support blueprint static folders as well you'll also need to use the AliasMatch directive:
AliasMatch "(?i)^/([^/]+)/static/(.*)$" "/path/to/app/blueprints-root/$1/static/$2"
<Directory ~ "/path/to/app/blueprints-root/[^/]+/static/.*">
Order allow,deny
Allow from all
</Directory>
See also: The Directory directive.
When using AddHandler
As Graham Dumpleton has pointed out in the comments, you can use mod_rewrite to pass requests off to Python if and only if a file does not exist in DocumentRoot. Quoting from the linked docs:
When using the AddHandler directive, with WSGI applications identified by the extension of the script file, the only way to make the WSGI application appear as the root of the server is to perform on the fly rewriting of the URL internal to Apache using mod_rewrite. The required rules for mod_rewrite to ensure that a WSGI application, implemented by the script file 'site.wsgi' in the root directory of the virtual host, appears as being mounted on the root of the virtual host would be:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /site.wsgi/$1 [QSA,PT,L]
Do note however that when the WSGI application is executed for a request the 'SCRIPT_NAME' variable indicating what the mount point of the application was will be '/site.wsgi'. This will mean that when a WSGI application constructs an absolute URL based on 'SCRIPT_NAME', it will include 'site.wsgi' in the URL rather than it being hidden. As this would probably be undesirable, many web frameworks provide an option to override what the value for the mount point is. If such a configuration option isn't available, it is just as easy to adjust the value of 'SCRIPT_NAME' in the 'site.wsgi' script file itself.
from your.app import app # Your Flask app
import posixpath
def application(environ, start_response):
# Wrapper to set SCRIPT_NAME to actual mount point.
environ['SCRIPT_NAME'] = posixpath.dirname(environ['SCRIPT_NAME'])
if environ['SCRIPT_NAME'] == '/':
environ['SCRIPT_NAME'] = ''
return app(environ, start_response)
This wrapper will ensure that 'site.wsgi' never appears in the URL as long as it wasn't included in the first place and that access was always via the root of the web site instead.

`web.py` sessions with Apache2

Question:
I am in the process of porting my web.py app from its built in server to Apache2 using mod_wsgi. All is well and the code executes, except for the sessions.
Firstly, note that the sessions work fine with the old server. I am testing as follows: I render a page called layout which has the lines
$session
${'loggedIn' in session}
Due to the fact that session (which is a web.sessions.Session) is initialised with initializer={'loggedIn' : False}, I expect the second line to always render as "True". This it does with the default server.
However, on Apache2 with mod_wsgi, it is not the case. If I restart apache, then it renders as True, but subsequent refreshes of the page render as False.
I understand that sometimes the cookie_path can be the culprit, but have set that to /, and am unsure of what else could be the problem.
Code:
/etc/apache2/apache2.conf
LoadModule wsgi_module modules/mod_wsgi.so
WSGIScriptAlias / /var/www/myapp/webUtils.py/
AddType text/html .py
<Directory /var/www/myapp>
Order deny,allow
Allow from all
</Directory>
/var/www/myapp/webUtils.py
import sys,os
abspath = os.path.dirname(__file__) or '.'
sys.path.append(abspath)
os.chdir(abspath)
import web
(...)
## The configuration for the sessions (this function just reads in
## the file and turns it into a dictionary).
session_configuration = config.getConfiguration('config/sessions.cfg')
for i in session_configuration:
web.config.session_parameters[i] = session_configuration[i]
web.config.debug = False
app = web.application(urls,globals(),autoreload=False)
session = web.session.Session(app,
web.session.DiskStore('/home/robert/sessions'),
initializer={'loggedIn' : False})
render = web.template.render('templates',
globals={'session':session},
base='layout')
# Get the WSGI stuff
application = app.wsgifunc()
config/sessions.cfg
timeout : 60*10
secret_key : "stuff"
cookie_name : "someName"
cookie_path : "/"
EDIT: Update
By running exhaustive tests, I have found that calling webUtils.session._load() as the first line in a GET fixes the whole problem. I thus postulate that the _processor of that Session is not being called (even though it is in app.processors). Why not is still a mystery.
You are using a multi process configuration and so cannot rely on an I'm memory session cache as subsequent requests can go to different processes. Also, since using embedded mode of mod_wsgi, Apache can decide to shutdown your processes if it thinks they are no longer needed.
You need to make sure you are using a database for the session cache.
Alternative using mod_wsgi daemon mode with the default of a single process.
Finally found the problem. It had to do with the multi processes, but ended up being that the Session object that created a hook (and thus got loaded every time) was not the same as the object that my page code was seeing. Thus if I loaded and saved my session in each GET statement and removed the hook, it all worked.
To solve this, I just needed to undo an assumption I made and reinstate the code
if web.config.get('_session') is None:
session = web.session.Session(app, web.session.DiskStore('sessions'), {'count': 0})
web.config._session = session
else:
session = web.config._session
which I had removed, since it is only given for the builtin server in the documentation.

Deploying a Flask application with CGI [duplicate]

This question already has answers here:
Deploy flask application on 1&1 shared hosting (with CGI)
(3 answers)
Closed 4 years ago.
I have written a small application using the Flask framework. I try to host this using cgi. Following the documentation I created a .cgi file with the following content:
#!/usr/bin/python
from wsgiref.handlers import CGIHandler
from yourapplication import app
CGIHandler().run(app)
Running the file results in following error:
...
File "/usr/lib/pymodules/python2.7/werkzeug/routing.py", line 1075, in bind_to_environ
wsgi_server_name = environ.get('HTTP_HOST', environ['SERVER_NAME'])
KeyError: 'SERVER_NAME'
Status: 500 Internal Server Error
Content-Type: text/plain
Content-Length: 59
In my application I have set:
app.config['SERVER_NAME'] = 'localhost:5000'
When I run the application with the Flask development server it works perfectly well.
As you can tell I'm very new to this stuff and I have search for others with similar errors but with no luck. All help is appreciated.
I will try to show what I've done and it is working in Godaddy sharing host account:
In the cgi-bin folder in MYSITE folder, I added the following cgi file:
#!/home/USERNAME/.local/bin/python3
from wsgiref.handlers import CGIHandler
from sys import path
path.insert(0, '/home/USERNAME/public_html/MYSITE/')
from __init__ import app
class ProxyFix(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
environ['SERVER_NAME'] = ""
environ['SERVER_PORT'] = "80"
environ['REQUEST_METHOD'] = "GET"
environ['SCRIPT_NAME'] = ""
environ['QUERY_STRING'] = ""
environ['SERVER_PROTOCOL'] = "HTTP/1.1"
return self.app(environ, start_response)
if __name__ == '__main__':
app.wsgi_app = ProxyFix(app.wsgi_app)
CGIHandler().run(app)
As you can see the init file in the MYSITE folder have the flask app.
The most important thing is to set the permissions right. I setted 755 to this folder permission AS WELL AS to "/home/USERNAME/.local/bin/python3" folder!! Remember that the system needs this permission to open flask.
To open the cgi I have the following .htaccess file in MYSITE folder:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /home/USERNAME/public_html/MYSITE/cgi-bin/application.cgi/$1 [L]
So it will render the cgi file when someone enters your page.
This is posted as an answer following the comments above for the sake of completeness.
As discussed above, cgi scripts should execute by some server. Here's the abstract from CGI 1.1 RFC:
The Common Gateway Interface (CGI) is a simple interface for running
external programs, software or gateways under an information server in
a platform-independent manner. Currently, the supported information
servers are HTTP servers.
For the environment variables (which were missing and triggered the error) see sectuib 4.1 in the RFC.

Django: only blank page

I have a server with Apache and I would like to start website written in Django. I user mod_wsgi. Now I have it prepared. But the respond of a server is empty. And in error log, there is nothing. Do you know what is the reason why?
If some file could help (*.wsgi, settings.py) I will append it.
Prochazky.wsgi
import os
import sys
import site
os.environ['PYTHON_EGG_CACHE'] = '/home/prochazky/venv/.python-eggs'
site.addsitedir('/home/prochazky/venv/lib/python2.6/site-packages')
os.environ['DJANGO_SETTINGS_MODULE'] = 'Prochazky.settings'
sys.path.append('/home/prochazky/')
sys.path.append('/home/prochazky/Prochazky/')
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Apache vhost:
<VirtualHost *:80>
WSGIScriptAlias / /home/prochazky/Prochazky/Prochazky.wsgi
ServerName testing.prochazky.net
DocumentRoot /home/prochazky
ErrorLog /home/prochazky/wsgi.log
</VirtualHost>
Trying getting a hello world program working first and not Django. Watch:
http://code.google.com/p/modwsgi/wiki/WhereToGetHelp?tm=6#Conference_Presentations
and read:
http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide
At a guess though, are you perhaps loading mod_python into the same Apache. An incompatible mod_python will cause exactly that symptom with merely a segmentation fault message in main Apache error log.
UPDATE 1
Are you loading mod_php into same Apache? It can sometimes have conflicting shared library requirements and will cause a crash. If you are also loading it, disable it from Apache configuration.
Also try setting:
WSGIApplicationGroup %{GLOBAL}
This will force use of main interpreter which will avoid problems with third party extensions that aren't written properly to work in sub interpreters.
You really though need to look more closely at the main Apache error log, not the virtual host one. Run a 'tail -f' on it when you make a request and check for sure you are seeing messages there, specifically a segmentation fault or similar message. Such a message about process crashing and causing empty page will not show in virtual host error log.
Is it possible the template file your root url/view is empty or evaluates to empty?
For instance, if you have a template like so:
{% extends "base.html" %}
{% block content %}blah blah{% endblock %}
and base.html doesn't use a block "content", then the content block from your template won't be used and your template will evaluate to empty despite having content.
This is from my setup (names altered to protect the innocent guilty).
<VirtualHost *:80>
ServerName site.domain.com
ServerAdmin webmaster#domain.com
WSGIScriptAlias / /home/user/site/django.wsgi
<Directory /home/user/site/>
Options FollowSymLinks
AllowOverride None
Order allow,deny
allow from all
</Directory>
... etc etc etc.
I think you need the <directory> to allow the server to access the .wsgi.
I'm really not an apache guru though so don't take this example as perfect. (I think all that is needed is the order Allow, deny and allow from all)
a good site to check out: http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango

Categories