I have a Tornado application that I want to host under a non-root location with nginx. So I have an nginx configuration that looks like
server {
listen 80;
server_name mysite.com;
location /myapp/ {
proxy_pass http://localhost:8888/;
}
}
I want the app to live at mysite.com/myapp/
. With the current configuration all of the Handlers are routed to the correct url however all of the links used in the templates are wrong. For example
<a href='/'>Home</a>
links to mysite.com/
rather than mysite.com/myapp/
. I'd also like the app to still work locally so I don't want /myapp/
hard-coded into the templates.
Is there a way to deal with this with either nginx or Tornado?
My solution thus far has been to add a convenience function to the template namespace
import tornado.ioloop
import tornado.web
import os
APPLICATION_ROOT = os.environ.get('MYAPP_ROOT')
class BaseHandler(tornado.web.RequestHandler):
def full_url(self, path, *args, **kwargs):
if path.startswith('/'):
path = path.lstrip('/')
return os.path.join(APPLICATION_ROOT, path)
else:
return path
def get_template_namespace(self):
"""Returns a dictionary to be used as the default template namespace.
May be overridden by subclasses to add or modify values.
The results of this method will be combined with additional
defaults in the `tornado.template` module and keyword arguments
to `render` or `render_string`.
"""
namespace = dict(
handler=self,
request=self.request,
current_user=self.current_user,
locale=self.locale,
_=self.locale.translate,
pgettext=self.locale.pgettext,
static_url=self.static_url,
xsrf_form_html=self.xsrf_form_html,
reverse_url=self.reverse_url,
full_url=self.full_url
)
namespace.update(self.ui)
return namespace
and set MYAPP_ROOT='/myapp/'
as an environment variable and use
<a href="{{ full_url('/') }}">Home</a>
in the templates.
Tornado doesn't have good support for applications that can be relocated to different paths like this - it's generally assumed that the path prefix is known and can be hard-coded. (The trailing slash in the nginx proxy_pass
directive is significant - remove it and nginx passes the request through as-is to Tornado)
If you still want to use different paths depending on whether you're going through nginx or not, I would recommend a URL helper function as you have here. Other options include always using relative paths instead of absolute ones in your URLs (will probably require using /myapp/home
and /home
instead of /myapp/
and /
for the home page), or having nginx rewrite your links as in this question