Imagine you have an Apache server set up with a virtualhost configuration listening to some domain, e.g.
my.domain:8080
You have a Flask app running at:
localhost:5000
You want to add a mod_proxy directive so that:
http://my.domain:8080/app_location/ ---> http://localhost:5000
Most resources will suggest the following:
ProxyPass /app_location/ http://localhost:5000/
# Wrong:
ProxyPassReverse /app_location/ http://localhost:5000/
However, you should follow the advice from this post and use:
ProxyPass /app_location/ http://localhost:5000/
ProxyPassReverse /app_location/ http://my.domain:8080/app_location/
The first line remains the same (forward all requests at location app_location
to this server over there), but the ProxyPassReverse
-line changes changes (ProxyPassReverse
will do a string replace in the HTTP Location headers). For Flask, however, you will have to use http://my.domain:8080/app_location/
as the target and not just http://my.domain:8080/
as the blog post above suggests.
Next up, you’ll might notice that url_for
is not working as expected, and is rewriting URLs without the app_location
appended to it, or using localhost
and not my.domain
. Solution as inspired by this snippet. First, create a class as follows:
from flask import Flask, flash, render_template, redirect, url_for, session, request, send_from_directory, abort
from flask import Response, Blueprint
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
import datetime
class ReverseProxied(object):
def __init__(self, app, script_name=None, scheme=None, server=None):
self.app = app
self.script_name = script_name
self.scheme = scheme
self.server = server
def __call__(self, environ, start_response):
script_name = environ.get('HTTP_X_SCRIPT_NAME', '') or self.script_name
if script_name:
environ['SCRIPT_NAME'] = script_name
path_info = environ['PATH_INFO']
if path_info.startswith(script_name):
environ['PATH_INFO'] = path_info[len(script_name):]
scheme = environ.get('HTTP_X_SCHEME', '') or self.scheme
if scheme:
environ['wsgi.url_scheme'] = scheme
server = environ.get('HTTP_X_FORWARDED_SERVER', '') or self.server
if server:
environ['HTTP_HOST'] = server
return self.app(environ, start_response)
Then set up your app using:
app = Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app, script_name='/app_location')