#36514 closed New feature (wontfix)
Improve ALLOWED_HOSTS error message: show both values
Reported by: | Klaas van Schelven | Owned by: | |
---|---|---|---|
Component: | HTTP handling | Version: | 5.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When Django rejects a request because the Host header doesn't match ALLOWED_HOSTS, the resulting error message shows
only the incoming header value:
Invalid HTTP_HOST header: 'localhost:8000'. You may need to add 'localhost' to ALLOWED_HOSTS.
This makes it harder to determine whether the problem is a misconfigured proxy (not setting the correct Host) or simply
a missing hostname in ALLOWED_HOSTS. In many cases, the advice to "add localhost" is actively unhelpful: production
deployments rarely serve requests at localhost, and the real fix is usually to configure the proxy correctly.
I’ve implemented a more helpful version of this logic in Bugsink (a Django app installed by users who may not be Django
developers). I describe that implementation in more detail in [this blog post about improving Django’s ALLOWED_HOSTS error messages](https://www.bugsink.com/blog/better-allowed-hosts/#better-error-messages).
In the "bugsink approach" the error:
- shows the actual Host header and the configured ALLOWED_HOSTS
- suggests the likely cause
- avoids pointing users towards "add localhost" as the default fix
Some of what I did in Bugsink likely goes beyond what Django should adopt by default (e.g. showing the error in the
browser), but the idea of displaying both values (the incoming host and the configured list) would be a broadly useful
change on its own.
If desired, the message could also give more specific advice depending on the values (e.g. distinguish between loopback
and public domains), but that can be considered separately.
Security considerations
Showing both the incoming Host header and the configured ALLOWED_HOSTS reveals limited information:
- The Host header is attacker-controlled — the client already knows what they sent.
- _or_ The Host header is simply a misconfiguration (in which case it's on-broken-deploy only)
- ALLOWED_HOSTS reveals the expected hostname(s). In most deployments, this is already visible in the TLS certificate.
Change History (5)
comment:1 by , 6 weeks ago
Component: | Uncategorized → HTTP handling |
---|---|
Resolution: | → wontfix |
Status: | new → closed |
Type: | Uncategorized → New feature |
comment:2 by , 6 weeks ago
In real world deployments, it's common to include internal hostnames, IP addresses, or ephemeral domains that are not externally visible, for example in environments where SSL termination and routing are handled separately from the Django app itself.
That's a fair point for the "this isn't a good fit for Django" case.
I'd argue that the following point remains: for the most common misconfiguration at the proxy level, Django now explicitly suggests to add localhost to ALLOWED_HOSTS. This is generally exactly the opposite of what you want. Could we say _that_ is a bug?
comment:3 by , 6 weeks ago
this is a pretty good example of the danger I'm talking about with 40 upvotes on Stackoverflow:
literally as the error suggested! go ahead and add the line
0.0.0.0 to the ALLOWED_HOSTS in your settings.py
comment:4 by , 6 weeks ago
echoing the full ALLOWED_HOSTS list in the error message
One more thing: the linked article combines the ideas of showing the DisallowedHost message in the browser with including ALLOWED_HOSTS in the output.
Could it not be argued that the latter is OK (even in the general case) provided the former isn't implemented?
comment:5 by , 4 weeks ago
The localhost
suggestion is taking the aberrant case as normal. Standardly the Host header is the domain of the site being requested, so something like djangoproject.com
, rather than localhost
.
In that case, the error message makes perfect sense:
Invalid HTTP_HOST header: 'djangoproject.com'. You may need to add 'djangoproject.com' to ALLOWED_HOSTS.
If you really want to make requests to localhost
, then absolutely it should be added to ALLOWED_HOSTS
.
I don't think we can account for every possible misunderstanding here.
To the original point: the contents of ALLOWED_HOSTS
should not be part of the error message.
Hello Klaas van Schelven, thank you for taking the time to create this ticket and for the detailed write-up.
I appreciate the motivation to improve the clarity of this error message, I have fought with that error myself. That said, I believe the proposed change introduces security concerns with limited practical benefit. In particular, echoing the full
ALLOWED_HOSTS
list in the error message could unintentionally disclose internal configuration details. While it's true that manyALLOWED_HOSTS
entries are public, that's not guaranteed. In real world deployments, it's common to include internal hostnames, IP addresses, or ephemeral domains that are not externally visible, for example in environments where SSL termination and routing are handled separately from the Django app itself. In such cases,ALLOWED_HOSTS
reflects internal routing constraints rather than externally resolvable hostnames.Given the above, I'll close this ticket as
wontfix
. If you disagree, and considering this a new feature request for Django, the feature idea should first be proposed and discussed with the community. To do that, please raise this on the new feature tracker.