What determines when mod_proxy only sometimes add internal ip addresses to X-Forwarded-For header
<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>