Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FastAPI (starlette) get client real IP

I have an API on FastAPI and i need to get the client real IP address when he request my page.

I'm ty to use starlette Request. But it returns my server IP, not client remote IP.

My code:

@app.post('/my-endpoint')
async def my_endpoint(stats: Stats, request: Request):
    ip = request.client.host
    print(ip)
    return {'status': 1, 'message': 'ok'}

What i'm doing wrong? How to get real IP (like in Flask request.remote_addr)?

like image 609
Nataly Firstova Avatar asked Feb 06 '20 15:02

Nataly Firstova


People also ask

How do I find my client IP address on FastAPI?

Use the Request object directly Let's imagine you want to get the client's IP address/host inside of your path operation function. For that you need to access the request directly. By declaring a path operation function parameter with the type being the Request FastAPI will know to pass the Request in that parameter.

How many requests can FastAPI handle?

FastAPI (Async) - Python FastAPI in asynchronous mode clocks in at ~228 requests per second.


Video Answer


2 Answers

request.client should work, unless you're running behind a proxy (e.g. nginx) in that case use uvicorn's --proxy-headers flag to accept these incoming headers and make sure the proxy forwards them.

like image 166
Hedde van der Heide Avatar answered Sep 21 '22 20:09

Hedde van der Heide


if you use the nginx and uvicorn,you should set proxy-headers for uvicorn,and your nginx config should be add HostX-Real-IPand X-Forwarded-For.
e.g.

server {
  # the port your site will be served on
    listen 80;
  # the domain name it will serve for
    server_name <your_host_name>; # substitute your machine's IP address or FQDN

#    add_header Access-Control-Allow-Origin *;
    # add_header Access-Control-Allow-Credentials: true;
    add_header Access-Control-Allow-Headers Content-Type,XFILENAME,XFILECATEGORY,XFILESIZE;
    add_header access-control-allow-headers authorization;
    # Finally, send all non-media requests to the Django server.
    location / {
        proxy_pass http://127.0.0.1:8000/; # the uvicorn server address
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    }
}

on the nginx document:

This middleware can be applied to add HTTP proxy support to an
application that was not designed with HTTP proxies in mind. It
sets REMOTE_ADDR, HTTP_HOST from X-Forwarded headers. While
Werkzeug-based applications already can use
:py:func:werkzeug.wsgi.get_host to retrieve the current host even if
behind proxy setups, this middleware can be used for applications which
access the WSGI environment directly。
If you have more than one proxy server in front of your app, set
num_proxies accordingly.
Do not use this middleware in non-proxy setups for security reasons.
The original values of REMOTE_ADDR and HTTP_HOST are stored in
the WSGI environment as werkzeug.proxy_fix.orig_remote_addr and
werkzeug.proxy_fix.orig_http_host
:param app: the WSGI application
:param num_proxies: the number of proxy servers in front of the app.  
like image 26
AllenRen Avatar answered Sep 18 '22 20:09

AllenRen