If you entrust your website to Cloudflare - as is the case with this site - you've probably noticed that out of the box, all of the hits to your web application appear to come from Cloudflare IP addresses. Of course, this is a typical side effect of any reverse proxy setup. If you've got a Django/nginx-powered site sitting behind Cloudflare, it's easy enough to pass the original visitor IP address through to nginx (and subsequently to Django) with some minor configuration tweaks and a few lines of code. This writeup is aimed towards developers using Django 1.10 or newer and the new-style middleware.
Setting up nginx
First, you'll need to tell nginx to recognize Cloudflare's IP ranges and the HTTP header Cloudflare uses to pass the original visitor IP. Cloudflare has published an excellent, concise info page on how to do this.
We just need to make one more minor addition to the nginx configuration. Since nginx itself is also acting as a reverse proxy to your Django instance (e.g. gunicorn or uwsgi), the real IP address must be passed through again via an HTTP header.
X-Real-IP is more or less the de facto standard name for this.
In your nginx global configuration or a vhost/server block:
proxy_set_header X-Real-IP $remote_addr;
If you're including the
/etc/nginx/proxy_params present on Ubuntu and some other Linux distributions, this directive may already be present.
Setting up Django
Finally, we can add some simple middleware to our Django app in order to apply the value of our
Using the new-style middleware classes introduced in Django 1.10:
class XRealIPMiddleware(object): def __init__(self, get_response): self.get_response = get_response def __call__(self, request): try: real_ip = request.META['HTTP_X_REAL_IP'] except KeyError: pass else: request.META['REMOTE_ADDR'] = real_ip return self.get_response(request)
Don't forget to add this middleware to the list of
MIDDLEWARE in your
Now you'll be able to transparently retrieve the actual IP address of the user in your views in the standard way, by referencing
request.META['REMOTE_ADDR']. This approach is preferable if you later decide to remove Cloudflare for some reason - no code changes are required.