When Flask.config['SERVER_NAME'] is set to a domain (_thedomain.com:8080_) it alters the route matching behavior. Requests on "subdomained" urls (_sub1.thedomain.com:8080/some/route_) then only resolve to subdomained Blueprints (Blueprints with their 'subdomain' attribute set). With app.config['SERVER_NAME'] set to None, subdomained url would also properly resolve to non-subdomained Blueprints.
In other words, the presence of app.config['SERVER_NAME'] effectively serves as an _implicit_ switch to subdomain matching behaviour for Blueprints.
(1) if this is intentional the documentation is not clear about it.
(2) the naming of that config is not very indicative of this behavior altering property either.
(3) this is not always the desirable behavior. Sometimes one still wants to use subdomains and set app.config['SERVER_NAME'], but does not want to map blueprints to subdomains. Such is the case for example, when using the value contained by app.config['SERVER_NAME'] to extract the subdomain info from the requested url in one's own user-defined function (a before_request handler for example). As it stands, the behavior altering property of app.config['SERVER_NAME'] forces developers in the latter use-case to set another more innocuous config property with the same value (e.g. app.config['SERVER_DOMAIN']).
I propose that a new config flag that will explicitly enable subdomain matching behavior be added. The presence of which would make app.config['SERVER_NAME'] mandatory (can't have subdomain support without it). But the presence of app.config['SERVER_NAME'] should not impose subdomain matching behavior.
I think the core problem is that people think SERVER_NAME does anything other than this. SERVER_NAME is supposed to do two things and that is documented:
However I can see that the feature is problematic for blueprints that do not have a subdomain set. What would you expect blueprints without subdomain should do? Maybe we can figure out what the exact issue is and provide an improvement over it.
I think the core problem is that blueprints with a subdomain set actually work if SERVER_NAME is not set. That was never intended.
In my sense the problem is the double duty of SERVER_NAME. It contains information necessary for URL generation (1), and it switches unrelated behaviour (2). There are situations where I would gladly use the former, without needing subdomain based routing. Furthermore, SERVER_NAME could be used in different contexts where subdomains are not mapped to blueprints. For instance, in multi-tenant applications, where you need to catch the subdomain in a before_request handler to allow the app to switch to the appropriate db schema.
My proposition is to have an additional configuration whose purpose would be to explicitly enable subdomain based routing, something like SUBDOMAIN_MATCH. The presence of which should require the presence of SERVER_NAME, but the reverse should not apply.
This bug just caused me a massive headache, because I expected SERVER_NAME to behave consistently with app.run(host, port). Example:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.config['SERVER_NAME'] = "127.0.0.1:5555" # fine
#app.config['SERVER_NAME'] = "0.0.0.0:5555" # fail
app.run()
I was using SERVER_NAME to set the host and port of my application, wich works fine, except when I set the host to 0.0.0.0. In this case, all requests return 404. I guess this may be a result of the implicit subdomain matching that is used here.
Please make this configuration behave consistently or at least add a proper warning in the documentation. Currently it implies that what I was doing should work just fine. it literally took me hours to figure this out :/
@Klamann strictly speaking, 0.0.0.0 is not an address but catcher-for-all-errors-in-routing-table.
Any process which listens on 0.0.0.0 essentially catches packets which routing can not deliver. Article on wikipedia about 0.0.0.0 is surprisingly concise and simplistic enough.
Agreed - the dual behaviour of SERVER_NAME makes for many headaches putting together a dynamic subdomains app, too. I've only just fully understood the current behaviour by reading this issue.
+1 for the solution presented by @ekoka above - i.e. the addition of a SUBDOMAIN_MATCH configuration, allowing folks to turn matching off if the intention is not to map subdomains along to blueprints. This should be set by default True, to keep behaviour consistent with previous versions.
@mitsuhiko I could put together a PR with the added configuration parameter and updated docs if you think that's useful?
I need SERVER_NAME set for generating URLs outside of web request context, but I don't want my views to stop working when a different subdomain (i.e. 'www') is used. How can I achieve this?
@revmischa that is a separate issue, and is solved by having your web server redirect other domains to the "canonical" domain. For example, they should intercept www.example.com and redirect to example.com.
I agree with @revmischa suggestion.
I am using Google App Engine. If I set SERVER_NAME, I could never use GAE's task/cronjob feature because internally GAE will call the url using myappname.appspot.com rather than my full domain name.
A quick fix would be for url_for to accept a _server_name parameter.
I think I agree at this point that SERVER_NAME should not change the routing. It does indeed cause issues in particular if ngrok and others is involved.
it causes a lot more problems then it solves. i'd like to have a "canonical" server name, but use the Host header for _external url construction by default.
@mitsuhiko I can say that I was surprised by this behavior more than once on different projects over time, having to rediscover it. I literally just minutes ago was taking someone new through the Flask tutorial and this came up, prompting me to review the documentation, my current practices around SERVER_NAME handling, and this bug report which you have responded to very recently to me at this time of writing.
Anyway, that's a pretty longwinded 馃憤 but 馃憤 indeed!
Most helpful comment
This bug just caused me a massive headache, because I expected
SERVER_NAMEto behave consistently withapp.run(host, port). Example:I was using
SERVER_NAMEto set the host and port of my application, wich works fine, except when I set the host to 0.0.0.0. In this case, all requests return 404. I guess this may be a result of the implicit subdomain matching that is used here.Please make this configuration behave consistently or at least add a proper warning in the documentation. Currently it implies that what I was doing should work just fine. it literally took me hours to figure this out :/