apache django Bad Request 400 debug=True [duplicate] - 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

Multiple Python Flask apps on single apache server losing sessions when session.clear is called on one of the apps

I have a couple of python 3.6 Flask apps running on my apache server using WSGI.
There are 2 different apps running on the same apache server:
www.example.com/lodge
www.example.com/dashboard
Both apps have a unique app.secret_key
The /dashboard app is a flask app with its own set of routes:
/dashboard/login
/dashboard/orders
/dashboard/staff
The login route calls session.clear() and lets the user enter their login information. A logged in token then gets stored in a session variable.
Both the /dashboard/orders and dashboard/staff routes have a decorator which checks for the existence of the logged in token in session and redirects to the login route if it does not exists.
The /lodge app is another simple Flask app with its own routes:
/lodge/welcome
/lodge/personal
/lodge/review
/lodge/confirmation
The welcome route also calls session.clear() and then displays a webform. When the user submits the webform, the personal route is called which stores those webform input values into session.
The issue that I am having is if I navigate to www.example.com/dashboard/login and login, I can then flick between the staff and orders routes no problems at all, however when I then open a new tab and go to www.example.com/lodge/welcome (which then calls session.clear) and then reopen the dashboard tab and try to go to the staff or orders route, I get redirected back to the login route as the session has been cleared.
httpd.conf:
<VirtualHost *:80>
WSGIScriptAlias /newapp "c:/lodge/lodge.wsgi"
<Directory "c:/lodge">
Require all granted
</Directory>
WSGIScriptAlias /dashboard "c:/dashboard/dashboard.wsgi"
<Directory "c:/dashboard">
Require all granted
</Directory>
</VirtualHost>
Side note, this does not happen if I access the dashboard app on http://example.com/dashboard and the lodge app on http://www.example.com/lodge
Answering my own question here.
I achieved multiple applications on the same apache server quite easily by changing the app configs for both apps. No virtual enviroments or tinkering with wsgi scripts needed!
Lodge app:
app = Flask(__name__)
app.config.from_object(__name__)
app.config.update(
SESSION_COOKIE_NAME = 'session_lodge',
SESSION_COOKIE_PATH = '/lodge/'
)
Dashboard app:
app = Flask(__name__)
app.config.from_object(__name__)
app.config.update(
SESSION_COOKIE_NAME = 'session_db',
SESSION_COOKIE_PATH = '/dashboard/'
)
The answeres by #m-dennis and #burhan-khalid porivded some insight to the problem so thanks for that!
Having multiple sub domains was not an option for me and I encountered the same issue when having both apps run in their own virtual enviroments.
Side note, this does not happen if I access the dashboard app on http://example.com/dashboard and the lodge app on http://www.example.com/lodge
This is actually the reason why you are seeing this behavior. Cookies are bound to domains and not paths.
Once you set a cookie at example.com, it is valid for all links, paths and URLs for that domain. It is not valid for www.example.com - this explains why it works if you run one of your apps on a different subdomain.
So what you are seeing is the proper behavior.
Try to use virtual environments. It seems that your flask apps running in one python execution thread. Here you can find, how to run your app(s) in a virtual environment.

Django REST framework: Basic Auth without debug

Got a problem with Basic authentication in Django REST framework when debug mode is turned off. I am using Django 1.8.4 and Django REST Framework 3.2.2.
Looks like it saves credentials for all computers with the same IP address when the first is logged in. But after some time it prompts for the username and password again.
However, this problem does not occur when the debug mode in Django REST framework settings is set to True. I would like to have the same behaviour when debug is turned off. What is causing the problem?
In settings.py file add the host/domain-name of the system to which django is allowed to serve.
Use:
ALLOWED_HOSTS = ['127.0.0.1'] or ALLOWED_HOSTS = ['localhost'] so that django can serve the localhost.
You may also add other IP address as you wish.
Example:
ALLOWED_HOSTS = ['127.0.0.1', '192.1.12.23']
Domain names can also be accepted:
ALLOWED_HOSTS = ['www.example.com']
If you wish to serve many hosts, you may simply use *, as shown:
ALLOWED_HOSTS = ['*']
This will serve Django to any host in the world.

Apache config for static site on root, and Django on sub-locations

I have a single Django app that handles two (or more) parts of site, for example an "admin" and an "api" sections of the site. I also have normal html pages for the rest of the site, where no Django is needed.
I want to have the static html site on the root of my site, and the Django app on some sub-locations, for example
www.example.com -> Apache static html site
www.example.com/admin/ -> Django app, serving the pages for the admin
www.example.com/api/ -> Django app, serving the pages for the api
At first I try to do so all form Django, using the urls like so:
# my_app/urls.py
...
url(r'^admin/', include('admin.urls')),
url(r'^api/', include('api.urls')),
url(r'^(?P<path>.*)$', ??????????),
...
But I couldn't figure out a good way to delegate the serving of those static pages to Apache. (It did work if I use url(r'^(?P<path>.*)$, 'django.views.static.serve', {'document_root': '/path/to/static/site'}), but the Django documentation forbids to use that on a production server.)
Then I tried with the apache configuration:
# httpd.conf
...
DocumentRoot /path/to/static/site
WSGIScriptAlias /admin /path/to/django/my_app/wsgi.py
WSGIScriptAlias /api /path/to/django/my_app/wsgi.py
...
This worked as far as requests to root returned the static site and requests to both "admin" and "api" would return the Django site, but within Django I found no way to distinguish if the request came from '/admin' or from '/api'. (Plus I'm not sure if having two WSGIScriptAlias pointing at the same wsgi might cause some problems.)
If someone knows of a way to achieve this without having to split my Django app into two (or more) parts it would be greatly appreciated.
I had the almost exact same problem. In Apaches virtual host config for the site use
WSGIScriptAliasMatch ^(/(admin|api)) /path/to/django/my_app/wsgi.py$1
instead of
WSGIScriptAlias /admin /path/to/django/my_app/wsgi.py
WSGIScriptAlias /api /path/to/django/my_app/wsgi.py
Check these Q&A for further information:
Django (wsgi) and Wordpress coexisting in Apache virtualhost
Reconfiguring Apache to serve website root from new php source and specific sub-urls from old django site

Set NewRelic app name per-request

I'd like to break some specific views from a django app out into a separate NewRelic application. The NewRelic python docs implies that I can set request.environ['newrelic.app_name'] and it will use my new value instead of the default one, but it doesn't appear to work.
eg. in my wsgi file:
from django.core.handlers.wsgi import WSGIHandler
import newrelic.agent
application = WSGIHandler()
newrelic.agent.initialize('/path/to/newrelic.ini') # defines app_name='1st_app'
application = newrelic.agent.wsgi_application()(application)
in my Django view:
def some_view(request, *args, **kwargs):
request.environ['newrelic.app_name'] = '2nd_app'
...
return HttpResponse(...)
You can split these views out in mod_wsgi, but it must be done at the server level and not with Django. Use the SetEnv directive in your Apache config instead. Since you want to change the app_name based on request, you will need to use the Location directive to identify which URL should be re-named.
For example:
<Location /some/url>
SetEnv newrelic.app_name 2nd_app
</Location>

How do I manipulate subdomains with Pyramid's url dispatch? [duplicate]

I'm looking to have multiple domains and subdomains on a single Pyramid instance. However, I can't seem to find any documentation on it. The last question referred to a glossary with very little information and no examples. Do any of you have any examples or can direct me to better documentation?
Pyramid is just a WSGI application. This means it's dependent on the HTTP_HOST environ key (set by the Host header) to determine the host of the application. It's all relative. Point-being that Pyramid has no restrictions on what it can accept, thus the world is your oyster and you can set it up to limit content to various domains however you'd like. This of course starts with what hosts your webserver is configured to feed to your application.
Assuming you're using URL dispatch, you might want to design some custom route predicates that check the request.host value for whatever you'd like. Returning False from that predicate will prevent that route from ever matching a request to that host.
This is a large topic, so it might help if you give some more specifics. For example, since Pyramid is relative, any URL you may want to generate from 'example.com' to redirect someone to 'sub.example.com' will need to be done via a pregenerator.
def pregen(request, elements, kw):
kw['_app_url'] = 'http://sub.example.com'
return elements, kw
def req_sub(info, request):
return request.host.startswith('sub')
config.add_route('sub_only', '/',
custom_predicates=(req_sub,),
pregenerator=pregen)
config.add_route('foo', '/foo')
config.add_view(view, route_name-'foo')
def view(request):
# redirect the user to "http://sub.example.com", regardless of whether
# request.host is "example.com" or "sub.example.com"
return HTTPFound(request.route_url('sub_only'))
If you have control over your hosting environment, I would strongly suggest keeping the domain stuff out of pyramid and handling it with a proxy server such as apache mod proxy, routing to subdomains in pyramid. Then you can easily switch any of the domain name to view routing without having anything fragile (like domain names) in your pyramid code. Your app code will be much cleaner this way, and far easier to change later.
Here's an Apache example of two domains going to one pyramid app, assuming we are serving the pyramid app somehow or another on port 5001 (gunicorn or whatever you want).
<VirtualHost *:80>
ServerName domain_2.com
ProxyPreserveHost On
# send all request to our app at /app1/*
ProxyPass / http://127.0.0.1:5001/app_1/
ProxyPassReverse / http://127.0.0.1:5001/app_1/
</VirtualHost>
<VirtualHost *:80>
ServerName domain_2.com
ProxyPreserveHost On
# send all request to our app at /app2/*
ProxyPass / http://127.0.0.1:5001/app_2/
ProxyPassReverse / http://127.0.0.1:5001/app_2/
</VirtualHost>
And here's an example of one domain going to several pyramid instances:
<VirtualHost *:80>
ServerName mydomain.com
ProxyPreserveHost On
# admin go to manager app on 5001
ProxyPass /media/manager/ http://127.0.0.1:5001/ retry=5
ProxyPassReverse /media/manager/ http://127.0.0.1:5001/
# downloads from server app on 5002
ProxyPass /media/server/ http://127.0.0.1:5002/ retry=5
ProxyPassReverse /media/server/ http://127.0.0.1:5002/
</VirtualHost>

Categories