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 domain2;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name domain1;
location /api/ {
# Dynamically set the CORS origin based on the incoming request
set $cors_origin "";
if ($http_origin ~* (http://localhost:4025|)) {
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 (/
or domain1
).