How can I prevent a user from accessing my app at example.appspot.com and force them to access it at example.com? I already have example.com working, but I don't want users to be able to access the appspot domain. I'm using python.
5 Answers
You can check if os.environ['HTTP_HOST'].endswith('.appspot.com')
-- if so, then you're serving from something.appspot.com
and can send a redirect, or otherwise alter your behavior as desired.
You could deploy this check-and-redirect-if-needed (or other behavior alteration of your choice) in any of various ways (decorators, WSGI middleware, inheritance from an intermediate base class of yours that subclasses webapp.RequestHandler
[[or whatever other base handler class you're currently using]] and method names different than get and post in your application-level handler classes, and others yet) but I think that the key idea here is that os.environ
is set by the app engine framework according to CGI standards and so you can rely on those standards (similarly WSGI builds its own environment based on the values it picks up from os.environ).

- 854,459
- 170
- 1,222
- 1,395
-
@Alex Martelli: How would be on Django? http://stackoverflow.com/questions/35286042/redirect-appspot-com-to-custom-domain-google-app-engine-django – Niks Jain Feb 09 '16 at 07:41
-
The ` – Alex Martelli Feb 09 '16 at 15:07
The code posted above has two problems - it tries to redirect secure traffic (which isn't supported on custom domains), and also your cron jobs will fail when Google call them on your appspot domain and you serve up a 301.
I posted a slightly modified version to my blog: http://blog.dantup.com/2009/12/redirecting-requests-from-appid-appspot-com-to-a-custom-domain
I've included the code below for convenience.
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
def run_app(url_mapping):
application = webapp.WSGIApplication(url_mapping, debug=True)
application = redirect_from_appspot(application)
run_wsgi_app(application)
def redirect_from_appspot(wsgi_app):
"""Handle redirect to my domain if called from appspot (and not SSL)"""
from_server = "dantup-blog.appspot.com"
to_server = "blog.dantup.com"
def redirect_if_needed(env, start_response):
# If we're calling on the appspot address, and we're not SSL (SSL only works on appspot)
if env["HTTP_HOST"].endswith(from_server) and env["HTTPS"] == "off":
# Parse the URL
import webob, urlparse
request = webob.Request(env)
scheme, netloc, path, query, fragment = urlparse.urlsplit(request.url)
url = urlparse.urlunsplit([scheme, to_server, path, query, fragment])
# Exclude /admin calls, since they're used by Cron, TaskQueues and will fail if they return a redirect
if not path.startswith('/admin'):
# Send redirect
start_response("301 Moved Permanently", [("Location", url)])
return ["301 Moved Peramanently", "Click Here %s" % url]
# Else, we return normally
return wsgi_app(env, start_response)
return redirect_if_needed

- 40,147
- 24
- 151
- 275
-
2Thanks, deployed your code (+1). I wonder why Google doesn't offer built-in solution for this, since they usually encourages good practices such as url canonicalization. – jholster Apr 25 '10 at 08:21
-
I wondered the same thing. It's actually quite annoying having to put this code into all my apps (and change the domains) :-( – Danny Tuppeny May 02 '10 at 16:57
def redirect_from_appspot(wsgi_app):
def redirect_if_needed(env, start_response):
if env["HTTP_HOST"].startswith('my_app_name.appspot.com'):
import webob, urlparse
request = webob.Request(env)
scheme, netloc, path, query, fragment = urlparse.urlsplit(request.url)
url = urlparse.urlunsplit([scheme, 'www.my_domain.com', path, query, fragment])
start_response('301 Moved Permanently', [('Location', url)])
return ["301 Moved Peramanently",
"Click Here" % url]
else:
return wsgi_app(env, start_response)
return redirect_if_needed

- 25,640
- 75
- 229
- 424
-
-
Got this working, but I don't think it's possible to make it work with static content, so that will still be accessible via appspot (and all the various version'd subdomains) :-( – Danny Tuppeny Dec 19 '09 at 18:43
-
1This code doesn't handle SSL or cron jobs. I've posted a slightly modified version in a new answer. – Danny Tuppeny Dec 30 '09 at 12:45
You can redirect it to your custom domain (here example.com
) by overriding the initialize
method in your webapp2.RequestHandler
base class the following way :
def initialize(self, *a, **kw):
webapp2.RequestHandler.initialize(self, *a, **kw)
if self.request.host.endswith('appspot.com'):
self.request.host = 'example.com'
self.redirect(self.request.url, permanent=True)

- 350
- 3
- 11
In case you are using webapp2, a slightly easier (depending on your use case) solution is possible using its DomainRoute
.
If this is your URL map:
url_map = [
('/', HomeHandler),
('/about', AboutHandler),
('/admin/(.+)', AdminHandler),
MailForwardHandler.mapping(),
]
application = webapp2.WSGIApplication(url_map, debug=True)
and the admin and mail should not redirect, then add the redirect routes as follows:
from webapp2_extras import routes
url_map = [
routes.DomainRoute('appid.appspot.com', [
routes.RedirectRoute('/', redirect_to='http://app.com', schemes=['http']),
routes.RedirectRoute('/about', redirect_to='http://app.com/about', schemes=['http']),
],
('/', HomeHandler),
('/about', AboutHandler),
('/admin/(.+)', AdminHandler),
MailForwardHandler.mapping(),
]
application = webapp2.WSGIApplication(url_map, debug=True)
This will, as specified, only redirect http, not https. It uses a permanent redirect (301), as desired.
You can also pass a function to redirect_to
, as described in the documentation, which should make it easier when you have lots of rules.

- 2,081
- 1
- 20
- 24