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).