title: What determines when mod_proxy only sometimes add internal ip addresses to X-Forwarded-For header
body: <p>I've been experimenting with Apache mod_proxy and mod_remoteip in order to confirm my understanding of the handling of X-Forwarded-For headers, particularly around how internal IP Addresses (e.g. 10.x.x.x or 192.168.x.x ranges) are being handled.</p>
  
  <p>It seems like mod_proxy doesn't always add the internal IP addresses to the X-Forwarded-For header, but I've been unable to find any documentation explaining the expected behavior for this.</p>
  
  <p>As far as I can tell, when the request initiates from an internal IP address, then mod_proxy will add internal IP addresses to the X-Forwarded-For header, but when the initial request comes from a public IP, mod_proxy does not seem to add any internal IP addresses to the X-Forwarded-For.</p>
  
  <p><strong>The Question</strong></p>
  
  <p>My question is: What are the rules that govern whether or not mod_proxy will append the calling IP address to the X-Forwarded-For header.</p>
  
  <p>The <a href="https://httpd.apache.org/docs/current/mod/mod_proxy.html" rel="nofollow noreferrer">documentation on mod_proxy</a> says:</p>
  
  <blockquote>
    <p>When acting in a reverse-proxy mode (using the ProxyPass directive, for example), mod_proxy_http adds several request headers in order to pass information to the origin server. These headers are:</p>
    
    <p><em>X-Forwarded-For</em> - 
        The IP address of the client.</p>
    
    <p><em>X-Forwarded-Host</em> - 
        The original host requested by the client in the Host HTTP request header.</p>
    
    <p><em>X-Forwarded-Server</em> - 
        The hostname of the proxy server.</p>
    
    <p>Be careful when using these headers on the origin server, since they will contain more than one (comma-separated) value if the original request already contained one of these headers. For example, you can use %{X-Forwarded-For}i in the log format string of the origin server to log the original clients IP address, but you may get more than one address if the request passes through several proxies.</p>
  </blockquote>
  
  <p>I read this as saying that the client IP address will always be appended to the X-Forwarded-For header, but that's not the behavior I'm observing.</p>
  
  <p>The rest of this question is the tests I've conducted and the behavior I've observed.</p>
  
  <p><strong>The Setup</strong></p>
  
  <p>I've setup two servers both running Apache with mod_proxy installed. I'll refer to these as One and Two.</p>
  
  <ul>
  <li>One has the (internal) IP address 10.0.7.1</li>
  <li>Two has the (internal) IP address 10.0.7.2</li>
  </ul>
  
  <p>One has the following ProxyPass directive so that requests to sub-paths of /proxyToTwo are sent to the equivalent sub-path under /proxyToOne on Two</p>
  
  <pre><code>&lt;Location "/proxyToTwo"&gt;
          ProxyPass http://10.0.7.2/proxyToOne
  &lt;/Location&gt;
  </code></pre>
  
  <p>Two has the following ProxyPass directive so that requests to sub-paths of /proxyToOne are sent back to One but without the /proxyToOne prefix</p>
  
  <pre><code>&lt;Location "/proxyToOne"&gt;
          ProxyPass http://10.0.7.1
  &lt;/Location&gt;
  </code></pre>
  
  <p>The effect of this is that when I issue requests to <code>http://One/proxyToTwo/foo</code> it's proxied as follows</p>
  
  <ol>
  <li>One receives the request, issues the following request to Two <code>http://10.0.7.2/proxyToOne/foo</code></li>
  <li>Two receives the request, issues the following request back to One <code>http://10.0.7.1/foo</code></li>
  <li>One receives a request for <code>/foo</code> and actually serves the resource</li>
  </ol>
  
  <p>So every request is bounced from one to two and back to one before being responded two.</p>
  
  <p><strong>Calling with an Internal IP</strong></p>
  
  <p>Using the above setup, I call One from Two using it's internal IP address:</p>
  
  <pre><code>curl http://10.0.7.1/proxyToTwo/foo
  </code></pre>
  
  <p>The X-Forwarded-For and X-Forwarded-Host headers received when One eventually gets the request for the <code>/foo</code> resource is what I expect below:</p>
  
  <pre><code>X-Forwarded-For: 10.0.7.2, 10.0.7.1
  X-Forwarded-Host: 10.0.7.1, 10.0.7.2
  </code></pre>
  
  <p>This is what I expect, that the request was proxied first through One then Two, and the requesting IP addresses are first the initial request from Two (curl) then the request from One (mod_proxy) and the final request (not in the header because it's the client IP of the connection being from Two (mod_proxy)</p>
  
  <p><strong>Calling with external IP</strong></p>
  
  <p>The unexpected behavior is that mod_proxy seems to behave differently when called from public IP. So Instead of calling One from Two, I call One from my local machine using the public address</p>
  
  <pre><code>curl http://35.162.28.102/proxyToTwo/foo
  </code></pre>
  
  <p>The X-Forwarded-Host is still what I expect:</p>
  
  <pre><code>X-Forwarded-Host: 35.162.28.102, 10.0.7.2
  </code></pre>
  
  <p>That is, the request was first proxied through One (using it's external address) then through Two.</p>
  
  <p>But the X-Forwarded-For header is showing only my (external) IP address:</p>
  
  <pre><code>X-Forwarded-For: 35.163.25.76
  </code></pre>
  
  <p>This suggests to me that the initial execution of mod_proxy is adding the X-Forwarded-For header with the client IP address. But then the subsequent proxying by Two doesn't append the address of One.</p>
  
  <p>I think this behavior is probably more useful than blindly appending the internal IP addresses to the header, but I can't find it documented anywhere so would like to ensure I fully understand it.</p>