Jason C
Jason C

Reputation: 40315

ProxyFix does not seem to be working (Flask behind nginx)

I have a server running nginx. I'm trying to set up a Flask application at a specific sub-URL (e.g. http://server/app/ maps to Flask application's /). If it matters, ultimately I intend for multiple Flask applications to run at various other sub-URLs on this same server.

I'm new to all of this so I've been running through tutorials, in particular I've followed these guides / posts:

I have a section in my nginx sites-available/default file like this:

        location /firmware {
                 proxy_pass http://localhost:6001;
                 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                 proxy_set_header X-Forwarded-Proto $scheme;
                 proxy_set_header X-Forwarded-Host $host;
                 proxy_set_header X-Forwarded-Prefix /firmware;
        }

It seems to be working fine (the Flask app is on 6001):

Also, I'm using ProxyFix in the Flask app to let the app know it's behind a proxy. I've got this bit of code when creating the application:

from flask import Flask
from werkzeug.middleware.proxy_fix import ProxyFix

app = Flask(__name__)

app.wsgi_app = ProxyFix(
    app.wsgi_app,
    x_for=1,
    x_proto=1,
    x_host=1,
    x_prefix=1
)

@app.route("/")
def ... ():
    ...

However, the Flask application still sees the request as /firmware/, rather than /. I've verified this by checking the output logs when running the app via flask, and also by adding a route for /firmware/ to test if it gets hit (it does). The / route does not get a hit.

The behavior is the same whether I run the application via flask or gunicorn, that doesn't seem to matter.

What step have I missed / what am I doing wrong here? Why is the Flask application still getting requests for /firmware/ even though I've set up ProxyFix and the HTTP headers?

Upvotes: 0

Views: 362

Answers (1)

0x00
0x00

Reputation: 1123

In nginx add a trailing slash to your proxy proxy_pass http://localhost:6001/;

From the nginx documentation about proxy_pass

If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:

location /name/ {
    proxy_pass http://127.0.0.1/remote/;
}

If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:

location /some/path/ {
   proxy_pass http://127.0.0.1;
}

So in your case without the trailing slash, nginx was passing the request to flask (gunicorn) as http://localhost:6001/firmware instead of http://localhost:6001/

Upvotes: 1

Related Questions