Flask request.remote_addr is wrong on webfaction and not showing real user IP

Question:

I just deployed a Flask app on Webfaction and I’ve noticed that request.remote_addr is always 127.0.0.1. which is of course isn’t of much use.

How can I get the real IP address of the user in Flask on Webfaction?

Thanks!

Asked By: Ignas Butėnas

||

Answers:

The problem is there’s probably some kind of proxy in front of Flask. In this case the “real” IP address can often be found in request.headers['X-Forwarded-For'].

Answered By: Rob Wouters

If there is a proxy in front of Flask, then something like this will get the real IP in Flask:

if request.headers.getlist("X-Forwarded-For"):
   ip = request.headers.getlist("X-Forwarded-For")[0]
else:
   ip = request.remote_addr

Update: Very good point mentioned by Eli in his comment. There could be some security issues if you just simply use this. Read Eli’s post to get more details.

Answered By: Ignas Butėnas

Rewriting the Ignas’s answer:

headers_list = request.headers.getlist("X-Forwarded-For")
user_ip = headers_list[0] if headers_list else request.remote_addr

Remember to read Eli’s post about spoofing considerations.

Answered By: Shankar Cabus

You can use request.access_route to access list of ip :

if len(request.access_route) > 1:
    return request.access_route[-1]
else:
    return request.access_route[0]

Update:

You can just write this:

    return request.access_route[-1]
Answered By: rezakamalifard

Werkzeug middleware

Flask’s documentation is pretty specific about recommended reverse proxy server setup:

If you deploy your application using one of these [WSGI] servers behind an HTTP [reverse] proxy you will need to rewrite a few headers in order for the application to work [properly]. The two problematic values in the WSGI environment usually are REMOTE_ADDR and HTTP_HOST… Werkzeug ships a fixer that will solve some common setups, but you might want to write your own WSGI middleware for specific setups.

And also about security consideration:

Please keep in mind that it is a security issue to use such a middleware in a non-proxy setup because it will blindly trust the incoming headers which might be forged by malicious clients.

The suggested code (that installs the middleware) that will make request.remote_addr return client IP address is:

from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, num_proxies=1)

Note num_proxies which is 1 by default. It’s the number of proxy servers in front of the app.

The actual code is as follows (lastest werkzeug==0.14.1 at the time of writing):

def get_remote_addr(self, forwarded_for):
    if len(forwarded_for) >= self.num_proxies:
        return forwarded_for[-self.num_proxies]

Webfaction

Webfaction’s documentation about Accessing REMOTE_ADDR says:

…the IP address is available as the first IP address in the comma separated list in the HTTP_X_FORWARDED_FOR header.

They don’t say what they do when a client request already contains X-Forwarded-For header, but following common sense I would assume they replace it. Thus for Webfaction num_proxies should be set to 0.

Nginx

Nginx is more explicit about it’s $proxy_add_x_forwarded_for:

the “X-Forwarded-For” client request header field with the $remote_addr variable appended to it, separated by a comma. If the “X-Forwarded-For” field is not present in the client request header, the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable.

For Nginx in front of the app num_proxies should be left at default 1.

Answered By: saaj
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.