I use a lighttpd reverse proxy to serve django with gunicorn. Now this config worked:

proxy.server = ("" => ( "" => (
    "host" => "",
    "port" => 8000,

Now i moved the gunicorn into a container and use:

proxy.server = ("" => ( "" => (
    "host" => "",
    "port" => 8000,

Now every request has the ip as seen by gunicorn. I would understand, if the reverse proxy obfuscates the real IP, but why did it work with localhost then?

for both i get

X-Forwarded-For: client-ip
X-Host: the.domain
X-Forwarded-Proto: http

where the client-ip is public ip space.

the requests comes from


nc: connect to 8000 from localhost ( 44953 [44953]


nc: connect to 8000 from host ( 60027 [60027]

the container itself has ip, the host-bridge has and the routes inside the container are:

default via dev eth0 dev eth0  proto kernel  scope link  src

the host has: dev bridge  proto kernel  scope link  src

EDIT: The X-Forwarded-For was the same for both requests. (Tested with nc -vlp 8000).


My bet? lighttpd is adding an X-Forwarded-For header, and Django has something hardcoded somewhere to know that is unlikely to be the real remote IP address if that header's present.

You should verify that the X-Forwarded-For header is present, then get Django to use that as the remote address (looks like the way to do that is here).

  • i added some more info. The X-Forwarded-For header seems correct, but its still not working. In both cases it should not be able to get ip info from the reverse proxy, so it must use the X-Forwarded-For header. – allo Jan 13 '15 at 0:40
  • @allo Right - in a default config, the application won't just blindly trust an X-Forwarded-For header, as that would be a security problem (clients can send whatever, the header should only be trusted from trusted proxies). Configuration in Django will be needed before it'll trust the X-Forwarded-For that lighttpd is sending. – Shane Madden Jan 13 '15 at 0:42
  • okay, corrected the question again. you may be right, as server/client are for the host scenario. – allo Jan 13 '15 at 0:46
  • gunicorn-docs.readthedocs.org/en/latest/deploy.html says this, too. But --forwarded-allow-ips=real-ip and --forwarded-allow-ips='*' do not work for me. – allo Jan 13 '15 at 1:02
  • 1
    Indeed, Django determines the real ip, and the ip determined by django is even logged in the gunicorn accesslog. I am using now a Middleware for the ip and it works: micahcarrick.com/django-ip-address-behind-nginx-proxy.html – allo Jan 13 '15 at 17:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.