1

I have Nginx running in a docker container on the same network as my Flask app. I set up a reverse proxy in Nginx for my Flask app (running on gunicorn), and then setup ProxyFix to reset the Flask routes to be corrected when using functions like url_for().

The problem I am having is that I use the docker container name in my proxy_pass in Nginx, and ProxyFix doesn't seem to reset it to the real origin of the request being passed. The X-Forwarded-Proto and X-Forwarded-Prefix took, so I know ProxyFix is at least partially working.

Nginx setup. api-service is the docker container name of the flask application. This conf file has been reduced to potentially relevant items for brevity:

http {
    upstream api-service {
        server api-service:5010;
    }

    # Redirect HTTP to HTTPS
    server {
        listen 80;
        listen [::]:80;

        server_name domain1.com domain2.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        listen [::]:443 ssl;

        http2 on;

        server_name domain1.com;

        location /api/ {
            # Dynamically set the CORS origin based on the incoming request
            set $cors_origin "";

            if ($http_origin ~* (http://localhost:4025|https://domain1.com)) {
                set $cors_origin $http_origin;
            }

            # Add basic CORS headers for all requests
            add_header 'Access-Control-Allow-Origin' $cors_origin always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
            add_header 'Access-Control-Allow-Headers' 'Accept, Content-Type, Authorization' always;

            # Handle CORS preflight (OPTIONS) requests
            if ($request_method = OPTIONS) {
                add_header 'Access-Control-Max-Age' 1728000;
                return 204;
            }

            # Handle other requests
            if ($request_method != OPTIONS) {
                add_header 'Access-Control-Allow-Credentials' 'true' always;
            }

            # Proxy to the API service
            proxy_pass http://api-service/;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Host $cors_origin;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Prefix /api;
            proxy_redirect off;
            proxy_connect_timeout 500s;
            proxy_send_timeout 500s;
            proxy_read_timeout 500s;
        }
    }
}

Flask:

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

What I'm ultimately trying to do is use url_for() to create the redirect_uri for Google OAuth:

authorization_url = client.prepare_request_uri(
   provider_data["authorize_url"],
   redirect_uri=url_for(
      "authorize.oauth2_callback", provider=provider, _external=True
   ),
   scope=provider_data["scopes"],
)

Right now, I am getting a redirect_uri like this and Google rejects it: https://api-service/api/authorize/callback/

Before I implemented ProxyFix it was creating a URL like this: http://api-service/authorize/callback which is why I know ProxyFix is at least partially doing its job.

My one thought is that maybe $cors_origin in my Nginx is not being set at the if statement and remains empty "" and that somehow causes the proxy_set_header X-Forwarded-Host $cors_origin to fallback to the docker container name? When I look at the request headers in the browser I see the proper origin, referrer, and host listed though (https://domain1.com/ or domain1.com).

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.