336

I'm making a website where users can log on and download files, using the Flask micro-framework (based on Werkzeug) which uses Python (2.6 in my case).

I need to get the IP address of users when they log on (for logging purposes). Does anyone know how to do this? Surely there is a way to do it with Python?

13 Answers 13

441

See the documentation on how to access the Request object and then get from this same Request object, the attribute remote_addr.

Code example

from flask import request
from flask import jsonify

@app.route("/get_my_ip", methods=["GET"])
def get_my_ip():
    return jsonify({'ip': request.remote_addr}), 200

For more information see the Werkzeug documentation.

Sign up to request clarification or add additional context in comments.

3 Comments

Some times, it can be useful: request.access_route[0]
As for nginx, it sends the real IP address under HTTP_X_FORWARDED_FOR so make sure you don't end up with localhost for each request.
You need to know whether you are behind a reverse proxy. No other way around it. If you are behind nginx proxy, then remote_addr will be localhost. But if you are behind proxy, then you can use header information; If not behind proxy, then header information can be spoofed. if using_reverse_proxy: ip = request.environ.get('HTTP_X_REAL_IP', request.headers.get( 'X-Forwarded-For', request.remote_addr)) else: ip = "" if not request.remote_addr else request.remote_addr set it in your site config.
137

Proxies can make this a little tricky, make sure to check out ProxyFix (Flask docs) if you are using one. Take a look at request.environ in your particular environment. With nginx I will sometimes do something like this:

from flask import request   
request.environ.get('HTTP_X_REAL_IP', request.remote_addr)   

When proxies, such as nginx, forward addresses, they typically include the original IP somewhere in the request headers.

Update See the flask-security implementation. Again, review the documentation about ProxyFix before implementing. Your solution may vary based on your particular environment.

3 Comments

This works when you set the appropriate fields in the config of your reverse proxy. Used in production.
@drahnr yes indeed. The above code works if in e.g. nginx you set: proxy_set_header X-Real-IP $remote_addr;
@pors - it works. i have the same settings in my nginx conf as you. but i still don't understand why the code: request.headers.get('X-Real-IP', request.remote_addr) doesn't work. Note, intuitively I'd get the value from headers and use the name 'X-Real-IP' as that's how my nginx conf is.
97

Actually, what you will find is that when simply getting the following will get you the server's address:

request.remote_addr

If you want the clients IP address, then use the following:

request.environ['REMOTE_ADDR']

8 Comments

Only if you’re behind a reverse proxy, no?
@minitech I would say that your code should not care whether you're behind a proxy or not. If this option works reliably irrespective of the reverse proxy and the other assumes you're not behind a reverse proxy, then this should be preferred. (I'd test this if I could easily set up a reverse proxy, but that would take more time than I have at the moment.)
@jpmc26: I see no reason why it should work at all. request.remote_addr sounds like a property that should get a remote address depending on whether the reverse proxy is trusted.
Using mod_wsgi, request.remote_addr returned the servers address every time. request.environ['REMOTE_ADDR'] got me the client's public IP address. Maybe I'm missing something?
@jpmc26 You frequently do need to care if you're behind a remote proxy. If you are, then the IP than connects to you will be of the remote proxy server, and you'll need to rely on the headers it adds to get the original client IP. If you're not, those headers typically won't be present, and you'll want to use the connection IP as the client IP. And you can't necessarily just check for the header and fall back to the connection IP if it's not present, because then if you're not behind a reverse proxy a client can spoof their IP, which in many circumstances will be a security issue.
|
62

The below code always gives the public IP of the client (and not a private IP behind a proxy).

from flask import request

if request.environ.get('HTTP_X_FORWARDED_FOR') is None:
    print(request.environ['REMOTE_ADDR'])
else:
    print(request.environ['HTTP_X_FORWARDED_FOR']) # if behind a proxy

1 Comment

This answer together with changing my nginx config according to this blog worked for me. calvin.me/forward-ip-addresses-when-using-nginx-proxy
39

I have Nginx and With below Nginx Config:

server {
    listen 80;
    server_name xxxxxx;
    location / {
               proxy_set_header   Host                 $host;
               proxy_set_header   X-Real-IP            $remote_addr;
               proxy_set_header   X-Forwarded-For      $proxy_add_x_forwarded_for;
               proxy_set_header   X-Forwarded-Proto    $scheme;

               proxy_pass http://x.x.x.x:8000;
        }
}

@tirtha-r solution worked for me

#!flask/bin/python
from flask import Flask, jsonify, request
app = Flask(__name__)

@app.route('/', methods=['GET'])
def get_tasks():
    if request.environ.get('HTTP_X_FORWARDED_FOR') is None:
        return jsonify({'ip': request.environ['REMOTE_ADDR']}), 200
    else:
        return jsonify({'ip': request.environ['HTTP_X_FORWARDED_FOR']}), 200

if __name__ == '__main__':
    app.run(debug=True,host='0.0.0.0', port=8000)

My Request and Response:

curl -X GET http://test.api

{
    "ip": "Client Ip......"
}

1 Comment

I have mixed @pegasus and yours answers, works well!
35

The user's IP address can be retrieved using the following snippet:

from flask import request
print(request.remote_addr)

1 Comment

This is not true if the app is running behind a proxy server like nginx. Which it often is in production.
10

httpbin.org uses this method:

return jsonify(origin=request.headers.get('X-Forwarded-For', request.remote_addr))

2 Comments

Returns 127.0.0.1 due to proxy, not very helpful.
Thanks, this was the only answer that worked for me.
10

If you use Nginx behind other balancer, for instance AWS Application Balancer, HTTP_X_FORWARDED_FOR returns list of addresses. It can be fixed like that:

if 'X-Forwarded-For' in request.headers:
    proxy_data = request.headers['X-Forwarded-For']
    ip_list = proxy_data.split(',')
    user_ip = ip_list[0]  # first address in list is User IP
else:
    user_ip = request.remote_addr  # For local development

1 Comment

Note: this is insecure if not served behind a proxy. Check out ProxyFix instead.
9

Here is the simplest solution, and how to use in production.

from flask import Flask, request
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
# Set environment from any X-Forwarded-For headers if proxy is configured properly
app.wsgi_app = ProxyFix(app.wsgi_app, x_host=1)

@app.before_request
def before_process():
   ip_address = request.remote_addr

Add include proxy_params to /etc/nginx/sites-available/$project.

  location / {
    proxy_pass http://unix:$project_dir/gunicorn.sock;
    include proxy_params;
  }

include proxy_params forwards the following headers which are parsed by ProxyFix.

$ sudo cat /etc/nginx/proxy_params 
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

1 Comment

If you are using Argo Tunnels, can confirm this works just with the code above, without touching anything. Seems like ProxyFix does its magic.
1

If You are using Gunicorn and Nginx environment then the following code template works for you.

addr_ip4 = request.remote_addr

Comments

0

This should do the job. It provides the client IP address (remote host).

Note that this code is running on the server side.

from mod_python import apache

req.get_remote_host(apache.REMOTE_NOLOOKUP)

Comments

0

I did not get any of the above work with Google Cloud App Engine. This worked, however

ip = request.headers['X-Appengine-User-Ip']

The proposed request.remote_addr did only return local host ip every time.

Comments

0

If using Cloudflare Argo Tunnels, use:

ip_address = request.environ['HTTP_CF_CONNECTING_IP']

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.