Monday, December 6, 2010

Request's IP address using django, Apache proxying through Nginx.

So I spent about 2 hours trying to figure out how to get the real IP address from the request objects when proxying through Nginx using Apache. I didn't find much documentation online about this topic so I figured that I should share.

Problem:
So you do something like this:
Class MyModel(models.Model):
...
def populate_meta(self, meta_data):
try:
if 'REMOTE_ADDR' in meta_data:
self.ip = meta_data['REMOTE_ADDR']
except KeyError:
pass

And you ./manage.py runserver and all works well, your IP addresses are recorded fine.

Then you set-up a production server with Nginx and Apache with a configuration that looks like this:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:81;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Magic-Header "secret";
client_max_body_size 10m;
proxy_set_header X-Real-IP $remote_addr;
}
location /static {
alias /srv/web/landing/landing/static/;
}
location /media {
alias /srv/web/landing/env/lib/python2.6/site-packages/django/contrib/admin/media/;
}
}

And then suddenly all the IP addresses are recorded as 127.0.0.1!

How to fix it:
Change your python code to the following:
Class MyModel(models.Model):
...
def populate_meta(self, meta_data):
try:
if 'HTTP_X_REAL_IP' in meta_data:
self.ip = meta_data['HTTP_X_REAL_IP']
except KeyError:
pass

That's it! Hope it helps.

0 comments: