62

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())
mrisher
  • 1,062
  • 2
  • 9
  • 15
  • set DEBUG = FALSE in django setting file. and try to restart apache server. – Nilesh Dec 02 '13 at 06:06
  • Why does DEBUG=FALSE make it more reliable? I have tried restarting and am not seeing any improvement. – mrisher Dec 02 '13 at 20:23
  • 6
    Is [ALLOW_HOSTS](https://docs.djangoproject.com/en/1.6/ref/settings/#std:setting-ALLOWED_HOSTS) set correctly? Django will reply with bad request, only in prod mode, if this is set incorrectly. If it's working correctly part of the time - perhaps clients are connecting via different hostnames, some of these hostnames may be missing from ALLOW_HOSTS. – Greg Lowe Dec 11 '13 at 04:55
  • Yes, you got it! Thank you, it was because production mode requires that setting. Wonder why it was intermittent, though... – mrisher Dec 18 '13 at 18:28
  • I did a `sudo apt-get update` and `sudo apt-get upgrade` on a working virtual server, and afterward, got the 400 BAD REQUEST. It led me to this post, and the solution was to add ALLOWED_HOSTS. I assume this is because the upgrade changed to Django 1.5 or above. Note [the **"Important"** comment here](https://www.djangoproject.com/weblog/2013/feb/19/security/#s-issue-host-header-poisoning): *"by default Django 1.3.6 and 1.4.4 set ALLOWED_HOSTS to allow all hosts. This means that to actually fix the security vulnerability you should define this setting yourself immediately after upgrading."* – HostileFork says dont trust SE Nov 24 '16 at 09:57

3 Answers3

108

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.

teewuane
  • 5,524
  • 5
  • 37
  • 43
  • Strange thing. This solution works only for localhost for me. When I'm trying to add `my_site.com` to ALLOWED_HOSTS (`127.0.0.1 my_site.com` in /etc/hosts) Bad Request (400) appears again. What's wrong? – Anton Aug 17 '14 at 00:46
  • @Anton What is your `DEBUG` set to? When you access your website via 'my_site.com' is there a setting that is changing the value of `DEBUG`? Could their be a typo in your `ALLOWED_HOSTS` setting? I need more info :) My guess is you have a typo in your `ALLOWED_HOSTS` setting and it's ignored when trying to access your website via '127.0.0.1' because that is setting DEBUG to False. When you are trying to access the site via 'my_site.com' your DEBUG is getting set to True and using `ALLOWED_HOSTS` which has a type. Do you have '.my_site.com' or 'mysite.com'? – teewuane Aug 18 '14 at 16:40
  • DEBUG set to False. I created a new clean project for testing so nothing can change the value of DEBUG (at least I hope so). I tried a lot of variants of ALLOWED_HOSTS: `ALLOWED_HOSTS = ['localhost', 'my_site.com', 'ubuntu-virtualbox']`. localhost and ubuntu-virtualbox -> works, my_site.com -> Bad Request, Then I tried to give access for all hosts: `ALLOWED_HOSTS = ['*']` with the same result. And even when I changed DEBUG to True, only localhost and ubuntu-virtualbox were available. my_site.com is still returning Bad Request May it be because of virtualenv or some system settings? – Anton Aug 19 '14 at 06:22
  • here is my question http://stackoverflow.com/questions/25357744/django-and-bad-request-400 .I can give more info there. It's too difficult to post code in comments. – Anton Aug 19 '14 at 06:30
  • Not having the site listed in ALLOWED_HOSTS was also my issue. I did need to restart Apache after changing it, though. Without restarting Apache, it continued to display the occasional http 400 bad request. – Joel B Aug 19 '14 at 19:43
  • Docs link is broken – Agey Sep 12 '16 at 07:10
  • @Agey Oh yeah, it appears that django 1.6 documentation is no longer available. I'll fix the link for django 1.7. – teewuane Sep 12 '16 at 17:05
9

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.

Yuji 'Tomita' Tomita
  • 115,817
  • 29
  • 282
  • 245
  • 1
    Bingo - after 45 minutes of hunting this down, your answer stuck out and sure enough, I had an underscore in the production domain (hosts file) but not in dev domain. Very hard to debug this with DEBUG=False. – staggart Oct 27 '15 at 03:52
1

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.

user3770635
  • 123
  • 6