Nginx Reverse Proxy – Prevent Overriding x-forwarded-for Header

nginxnginx-reverse-proxyreverse-proxy

I have an nginx server behind a load balancer, the nginx server passes requests on to a variety of services, but in this case a docker container running apache. The load balancer sets an X-Forwarded-For correctly, but by the time it gets to the docker container, X-Forwarded-For has been set to the LB IP.

I have this in nginx config:

/etc/nginx/conf.d/real_ip.conf
set_real_ip_from {{LB IP}};
real_ip_header X-Real-IP;
real_ip_recursive on;

and this is the virtualhost:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name *.domain domain;
    include /etc/nginx/snippets/domain_ssl.conf;

  add_header X-Nginx-Debug "hi";

  proxy_pass_request_headers on;

  location    / {
    proxy_pass_request_headers on;
    proxy_pass  http://container-php;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Remote-Addr $remote_addr;
    proxy_set_header X-Real-IP $http_x_real_ip;
    proxy_set_header X-Header-Test "Hello World - $http_x_forwarded_for";
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

But what I get from the container is:

array(19) {
  ["Connection"]=>
  string(7) "upgrade"
  ["Host"]=>
  string(19) "domain"
  ["X-Forwarded-For"]=>
  string(12) "{{LB IP}}"
  ["X-Header-Test"]=>
  string(13) "Hello World -"
  ["X-Forwarded-Proto"]=>
  string(5) "https"
  ["cache-control"]=>
  string(9) "max-age=0"
  ["sec-ch-ua"]=>
  string(64) "" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97""
  ["sec-ch-ua-mobile"]=>
  string(2) "?0"
  ["sec-ch-ua-platform"]=>
  string(9) ""Windows""
  ["upgrade-insecure-requests"]=>
  string(1) "1"
  ["user-agent"]=>
  string(114) "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"
  ["accept"]=>
  string(135) "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
  ["sec-fetch-site"]=>
  string(4) "none"
  ["sec-fetch-mode"]=>
  string(8) "navigate"
  ["sec-fetch-user"]=>
  string(2) "?1"
  ["sec-fetch-dest"]=>
  string(8) "document"
  ["accept-encoding"]=>
  string(17) "gzip, deflate, br"
  ["accept-language"]=>
  string(26) "en-GB,en-US;q=0.9,en;q=0.8"
}

Notably X-Real-IP, X-Fowarded-For don't seem to be set, nor does remote_addr. Files served directly from nginx have x-forwarded-for set properly, so the LB is sending down the right header.

Have I missed a step?

Best Answer

I think the problem is in your real ip configuration.

set_real_ip_from {{LB IP}};

real_ip_header X-Real-IP;

real_ip_recursive on;

When real_ip_header should be (in your case) set to X-Forwarded-For. I'll assume your X-Forwarded-For header from LB looks like this :

X-Forwarded-For: {{Original client ip}}, {{LB ip}}

So when you set real_ip_header (The header used to replace client ip) to X-Forwarded-For it will match the original client ip. The Original client should now be under the variable $realip_remote_addr, which you can address to proxy_set_header X-Forwarded-For :

proxy_set_header X-Forwarded-For $realip_remote_addr

Please let me know if I have been of any help !

Related Topic