librelist archives

« back to archive

Running behind proxy with URL prefix other than /

Running behind proxy with URL prefix other than /

From:
Peter Hansen
Date:
2010-07-21 @ 15:09
I know the basics behind the issues of running a web app behind a proxy 
with a URL prefix other than "/", but I don't know how to configure this 
with Flask (or Werkzeug) and haven't had any luck googling for results 
yet (mostly involving "SCRIPT_NAME").

I have an app that runs fine on http://localhost:5000/.  I'd like to run 
it behind a server that expose it under https://someserver.foo/prefix/.

I think this might be handled easily with FastCGI, but I'm not using 
that just yet.  If necessary I can switch to it.  For now I'm just 
running the development HTTP server with a regular nginx "proxy_pass" 
statement.

I can live without the https part, for now, but I don't think that's 
part of the problem here anyway.

Basically, how can I configure my app so it tells wsgi (or whatever) 
that it is below "/prefix"?  I believe this involves setting up the wsgi 
environ to have SCRIPT_NAME="/prefix", but I could be wrong about that. 
  Either way, I can't find anything in the docs to tell me how I would 
do that, nor can I figure it out (yet) from the source.

An example showing how to reconfigure the Hello World app at 
http://flask.pocoo.org/ would be much appreciated!

-Peter

Re: [flask] Running behind proxy with URL prefix other than /

From:
Peter Hansen
Date:
2010-07-21 @ 17:28
On 2010-07-21 11:09 AM, Peter Hansen wrote:
> Basically, how can I configure my app so it tells wsgi (or whatever)
> that it is below "/prefix"?  I believe this involves setting up the wsgi
> environ to have SCRIPT_NAME="/prefix", but I could be wrong about that.

I've traced this to werkzeug.routing.Map.bind_to_environ() where it will 
extract SCRIPT_NAME and wsgi.url_scheme from the wsgi environment and 
pass those to bind() as the script_name and url_scheme arguments, 
respectively.

Now all I have to do is figure out how to configure my Flask app so that 
the wsgi environment contains the right SCRIPT_NAME when just running as 
a regular web server (i.e. not FastCGI).

--
Peter

Re: [flask] Running behind proxy with URL prefix other than /

From:
Simon Sapin
Date:
2010-07-21 @ 17:47
Le 21/07/2010 19:28, Peter Hansen a écrit :
> On 2010-07-21 11:09 AM, Peter Hansen wrote:
>    
>> Basically, how can I configure my app so it tells wsgi (or whatever)
>> that it is below "/prefix"?  I believe this involves setting up the wsgi
>> environ to have SCRIPT_NAME="/prefix", but I could be wrong about that.
>>      
> I've traced this to werkzeug.routing.Map.bind_to_environ() where it will
> extract SCRIPT_NAME and wsgi.url_scheme from the wsgi environment and
> pass those to bind() as the script_name and url_scheme arguments,
> respectively.
>
> Now all I have to do is figure out how to configure my Flask app so that
> the wsgi environment contains the right SCRIPT_NAME when just running as
> a regular web server (i.e. not FastCGI).
>
> --
> Peter
>    

Hi,

You could fix SCRIPT_NAME with a WSGI middleware :

class FixScriptName(object):
     def __init__(self, app):
         self.app = app

     def __call__(self, environ, start_response):
         # fix SCRIPT_NAME in environ
         return self.app(environ, start_response)

my_flask_app.wsgi_app = FixScriptName(my_flask_app.wsgi_app)

Regards,
-- 
Simon Sapin

Re: [flask] Running behind proxy with URL prefix other than /

From:
Peter Hansen
Date:
2010-07-21 @ 20:09
On 2010-07-21 1:47 PM, Simon Sapin wrote:
 > You could fix SCRIPT_NAME with a WSGI middleware :
[snip]

I had temporarily hacked a solution by subclassing the Flask app class 
and overriding request_context(), adjusting the environment before the 
_RequestContext was created from it.

After getting that working, I thought I'd try the middleware approach. 
I'd never written any before, but with your simple example as a guide it 
wasn't too hard.

Better yet, rather than specifying URL scheme and prefix from the 
command line, as I had been doing, I was able to pull the info 
automatically from headers I added in nginx.  Here's the solution:

The nice thing is that werkzeug.router.Map directly supported all this. 
The trick is simply figuring out how to arrange for the right 
environment to let it work.

class ReverseProxied(object):
     '''Wrap the application in this middleware and configure the 
front-end server
     to add these headers, to let you quietly bind this to a URL other 
than /
     and to an HTTP scheme that is different than what is used locally.

     In nginx:
         location /myprefix {
             proxy_pass http://192.168.0.1:5001;     # where Flask app runs
             proxy_set_header Host $host;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             proxy_set_header X-Scheme $scheme;
             proxy_set_header X-Script-Name /myprefix;
             }

     :param app: the WSGI application
     '''
     def __init__(self, app):
         self.app = app

     def __call__(self, environ, start_response):
         script_name = environ.get('HTTP_X_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', '')
         if scheme:
             environ['wsgi.url_scheme'] = scheme
         return self.app(environ, start_response)


Installed in app using:

    app = Flask(__name__)
    app.wsgi_app = ReverseProxied(app.wsgi_app)


Thanks for the nudge, Simon!

--
Peter

Re: [flask] Running behind proxy with URL prefix other than /

From:
Simon Sapin
Date:
2010-07-21 @ 20:20
Le 21/07/2010 22:09, Peter Hansen a écrit :
> Here's the solution:
>    

Great! You could write a snippet so that others find it more easily than 
here : http://flask.pocoo.org/snippets/

The good thing with your solution is that it works with any WSGI app, 
not just Flask.

Regards,
-- 
Simon Sapin

Re: [flask] Running behind proxy with URL prefix other than /

From:
Peter Hansen
Date:
2010-07-21 @ 20:55
On 2010-07-21 4:20 PM, Simon Sapin wrote:
> Great! You could write a snippet so that others find it more easily than
> here : http://flask.pocoo.org/snippets/
>
> The good thing with your solution is that it works with any WSGI app,
> not just Flask.

I suppose it does.  Well, let's just leave it in the Flask snippets page 
to give the site some more traffic, if Armin's provider can handle it. :)

See http://flask.pocoo.org/snippets/35/

(By the way, Armin, a Deployment category may be appropriate.)

--
Peter

Re: [flask] Running behind proxy with URL prefix other than /

From:
Armin Ronacher
Date:
2010-07-21 @ 23:34
Hi,

On 7/21/10 9:55 PM, Peter Hansen wrote:
> (By the way, Armin, a Deployment category may be appropriate.)
Added category and moved snippet.


Regards,
Armin