Plainnotes

Getting the real client IP behind a reverse proxy

2025-11-05 · 2 min readDeploy

Application logs show 127.0.0.1 or an internal load balancer address because requests pass through a proxy.

In nginx:

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;

The application must trust this header **only from known proxies**. Otherwise anyone can send X-Forwarded-For: 1.2.3.4 and forge their origin. Express's trust proxy, Django's forwarded-host settings and Spring's forward-headers-strategy all need specific addresses, never *.

With several proxies the header is a comma-separated list; the real client is the last address before the first untrusted hop.