Make Flask's url_for use the 'https' scheme in an AWS load balancer without messing with SSLify
I was having these same issues with `redirect(url_for('URL'))' behind an AWS Elastic Load Balancer recently & I solved it this using the werkzeug.contrib.fixers.ProxyFixcall in my code.example:
from werkzeug.contrib.fixers import ProxyFixapp = Flask(__name__)app.wsgi_app = ProxyFix(app.wsgi_app)
The ProxyFix(app.wsgi_app)
adds HTTP proxy support to an application that was not designed with HTTP proxies in mind. It sets REMOTE_ADDR, HTTP_HOST from X-Forwarded headers.
Example:
from werkzeug.middleware.proxy_fix import ProxyFix# App is behind one proxy that sets the -For and -Host headers.app = ProxyFix(app, x_for=1, x_host=1)
Digging around Flask source code, I found out that url_for
uses the Flask._request_ctx_stack.top.url_adapter
when there is a request context.
The url_adapter.scheme
defines the scheme used. To make the _scheme
parameter work, url_for
will swap the url_adapter.scheme
temporarily and then set it back before the function returns.
(this behavior has been discussed on github as to whether it should be the previous value or PREFERRED_URL_SCHEME)
Basically, what I did was set url_adapter.scheme
to https with a before_request handler. This way doesn't mess with the request itself, only with the thing generating the urls.
def _force_https(): # my local dev is set on debug, but on AWS it's not (obviously) # I don't need HTTPS on local, change this to whatever condition you want. if not app.debug: from flask import _request_ctx_stack if _request_ctx_stack is not None: reqctx = _request_ctx_stack.top reqctx.url_adapter.url_scheme = 'https'app.before_request(_force_https)