Open duz-sg opened 4 years ago
Do you have --proxy-headers
param for uvicorn?
Do you have
--proxy-headers
param for uvicorn?
Thank you for the suggestion, just got some time to revisit this issue, I have made these changes, but the issue still remains.
This is my new start.sh
:
exec gunicorn -k "$WORKER_CLASS" -c "$GUNICORN_CONF" --proxy-protocol --proxy-allow-from '*' --forwarded-allow-ips '*' "$APP_MODULE"
In the backend, the request headers show they are from the internal proxy:
{'host': 'example.com', 'content-length': '95', 'accept': '*/*', 'accept-encoding': 'gzip', 'authorization': 'Bearer xxxxxxxxxxxx', 'content-type': 'application/json', 'x-forwarded-for': '10.0.38.40', 'x-forwarded-host': 'example.com', 'x-forwarded-port': '80', 'x-forwarded-proto': 'http', 'x-forwarded-server': '67b6a6b946de', 'x-real-ip': '10.0.38.40'}
Additionally, I tested some options in traefik-host.yml
, but does not work:
--entryPoints.http.forwardedHeaders.trustedIPs=127.0.0.1/32,192.168.1.7
--entryPoints.https.forwardedHeaders.trustedIPs=127.0.0.1/32,192.168.1.7
--providers.docker.useBindPortIP=true
@duz-sg if you are using docker swarm see https://github.com/moby/moby/issues/25526
Perhaps this helps: https://github.com/tomwojcik/starlette-context
See docs for more plugins: https://starlette-context.readthedocs.io/en/latest/plugins.html#forwarded-for
Example with FastAPI:
from starlette_context import middleware, plugins
app = FastAPI()
app.add_middleware(
middleware.ContextMiddleware,
plugins=(
plugins.ForwardedForPlugin(),
),
)
Access it like this:
from starlette_context import context
@app.get("/")
def hello():
forwarded_for = context.data["X-Forwarded-For"]
return {"hello": "world", "forwarded_for": forwarded_for}
I can't believe it took me almost a month to stumble upon this GEM! I have my application running on kubernetes and always thought that something was wrong with the ingress controller! Thanks @visini.
This Stack Overflow issue, "FastAPI (starlette) get client real IP", is highly relevant here.
In my case, for example, Gunicorn is running behind an Nginx reverse proxy as described on Deploying Gunicorn - Nginx Configuration
you need to tell Gunicorn to trust the X-Forwarded-* headers sent by Nginx. By default, Gunicorn will only trust these headers if the connection comes from localhost - Deploying Gunicorn Nginx Configuration Documentation
gunicorn --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 --chdir srv main:app --forwarded-allow-ips '*' --access_log_format = '%({x-forwarded-for}i)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' --accesslog ="-"
A quick way to test if you get the x-forwarded-for
from the request header is to enter the gunicorn
command above and examine the access log that is redirected to stdout
Bottom line is that for most cases you should not mess with Starlette's Request class unless there is a good reason. After all that is why FastAPI has been built on top of this library.
In my case the following FastAPI using-request-directly code example from the documentation page works fine without any modifications and you do get the real IP of the client:
from fastapi import FastAPI, Request
app = FastAPI()
@app.get("/items/{item_id}")
def read_root(item_id: str, request: Request):
client_host = request.client.host
return {"client_host": client_host, "item_id": item_id}
PS: If you deploy FastAPI as an Azure WebApp then the case I described perfectly fits because Azure is using gunicorn behind Nginx reverse proxy
I was trying to get client IP with
request.client.host
, and followed the documentation on https://dockerswarm.rocks/traefik-v1/traefik/#getting-the-client-ip, but it does not seem to work.From the log, I'm still getting
The output from
logger.info(request.client.host)
has the same result10.0.5.18
, this should be the IPtraefik
assigned internally, not the expected client IP.Is there anything I'm missing to configure?