Introduction
I have a Flask-application that is externally accessed via an nginx proxy. Using this configuration I encountered a problem to access the full content, described below.
After some investigation, I found out that the fix for this problem was to set the value of a WSGI environment
variable named SCRIPT_NAME
.
Description
A web-client access the link https://www.viltstigen.se/tv_ws?stn=Lund.
The web-server at domain viltstigen.se
is a nginx proxy, that passes the request to another node in my network that
is running gunicorn/flask application stack. Flask generates html content that is passed back to the original web-client.
In the html-template that flask is using to generate html code, I have
<script src="{{ url_for('static', filename='ws.js') }}"></script>
which in turn will generate this
<script src="static/ws.js"></script>
which causes the web-client to request https://www.viltstigen.se/static/ws.js
which in turn causes a 404 return.
What we want instead is
<script src="tv_ws/static/ws.js"></script>
that becomes https://www.viltstigen.se/tv_ws/static/ws.js
.
So how to get tv_ws
into the URL?
An extensive description is found here.
It boils down to setting the value of the WSGI environment variable SCRIPT_NAME
to tv_ws
.
If you set SCRIPT_NAME=/tv_ws
, WSGI guarantees that the web server running the app will strip this prefix from
incoming URLs, and add it to outgoing URLs.
Here is how I do it in my flask application
class ReverseProxied(object):
def __init__(self, app, script_name):
self.app = app
self.script_name = script_name
def __call__(self, environ, start_response):
environ['SCRIPT_NAME'] = self.script_name
return self.app(environ, start_response)
app = Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app, script_name='/tv_ws')
Note that if SCRIPT_NAME
already have a value (default value is "") it will be overwritten.
Here, the wsgi_app
object of the flask app is extended with the ReverseProxied-class. According to the
WSGI specification, the application should call
start_response (which is a server callback function), this is done within flask. The extended flask application sets
the value of SCRIPT_NAME
and call the original flask application object.
Several other solutions are discussing of setting the configuration of nginx instead, as an example see https://stackoverflow.com/questions/25962224/running-a-flask-application-at-a-url-that-is-not-the-domain-root