Pass Real IP to NGINX when running in Container

I am running into a unique issue. I run an NGINX container through Docker for Windows using WSL backend, listening to 443 for my domain and various subdomains. I have the below set up to pass through Real-IPs

	include /config/nginx/cf_real-ip.conf;
	real_ip_header X-Forwarded-For;
	set_real_ip_from 172.20.0.0/16;
    real_ip_recursive on;

The cf_real-ip.conf file contains a bunch of IPs from Cloudflare, e.g.

set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
set_real_ip_from 172.20.0.0/16;

When I proxy my domain through Cloudflare, it seems to pick up these various Cloudflare IPs fine and passes along the original, real-ip of the client perfectly fine. However, I have run into a unique issue where I need to have one of my subdomains not proxied through their CDN. This means the request would come directly to my router on port 443 without a Cloudflare IP. However, with this setup, I receive the IP of the client as 172.20.0.100 which is actually the IP of my NGINX container. I cannot for the life of me understand why. I assume it has something to do with this very old issue: Original ip is not passed to containers … · Issue #157 · docker/roadmap (github.com)

Basically, Docker is not forwarding the Original IP, so it gets lost and even though NGINX is set to recursively find the last non-trusted IP, there is none, so it just gives the last IP it has. But, if that is the case, why is it working when proxied from Cloudflare? Docker must be passing along the Cloudflare IP (the Original IP) along with its forwarded IPs, so NGINX can properly discover the client IP. I cannot see why it works in one scenario but not the other. Is this an NGINX configuration issue or a Docker issue?

I tried disabling Userland Proxy as well, but it didn’t help. I don’t know if I should keep that disabled as I see there is a feature open to have it disabled by default - Disable Userland proxy by default · Issue #14856 · moby/moby (github.com)

Unfortunately, I need to have one subdomain remain unproxied from Cloudflare. But this is a significant security risk if I cannot see the actual IP of the original client as all possible types of logic, e.g. fail2ban or geoblocking, would not be functional. So would really appreciate some help in discovering the underlying issue and workaround

1 Like

Did you ever find a solution for this? I’m in a similar situation

Nope. Paid Docker Desktop support has really degraded in quality, with requests often getting ignored. Honestly, I have not updated past 4.12.0 yet since anything after that has made such significant changes to the networking in Docker Desktop that I end up with numerous additional issues. I’m not sure if one of the more recent versions fixes this issue, but I doubt it.

Definitely looking for a solution/alternatives though

2 Likes