How to get user IP after updating commit b4a3389

After updating

All users’ last used addresses have changed to the Docker gateway, such as 172.17.0.1

My setup is as follows

Cloudflare → VPS Nginx → Discourse Docker Nginx → Discourse

I have a similar setup like you do, here is what I’ve added to my host nginx config so it will pass the user’s IP:

location / {
  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 104.16.0.0/13;
  set_real_ip_from 104.24.0.0/14;
  set_real_ip_from 108.162.192.0/18;
  set_real_ip_from 131.0.72.0/22;
  set_real_ip_from 141.101.64.0/18;
  set_real_ip_from 162.158.0.0/15;
  set_real_ip_from 172.64.0.0/13;
  set_real_ip_from 173.245.48.0/20;
  set_real_ip_from 188.114.96.0/20;
  set_real_ip_from 190.93.240.0/20;
  set_real_ip_from 197.234.240.0/22;
  set_real_ip_from 198.41.128.0/17;
  set_real_ip_from 2400:cb00::/32;
  set_real_ip_from 2405:8100::/32;
  set_real_ip_from 2405:b500::/32;
  set_real_ip_from 2606:4700::/32;
  set_real_ip_from 2803:f800::/32;
  set_real_ip_from 2a06:98c0::/29;
  set_real_ip_from 2c0f:f248::/32;

  real_ip_header X-Forwarded-For;

  proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;

  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Host $http_host;
  proxy_set_header X-Forwarded-Proto $scheme;

  proxy_http_version 1.1;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto https;
}

hello @CLOUD_PHT - welcome to Meta :slight_smile:

i assume you are running more than one website on the same machine configuration? (like a wordpress site + discourse)

the issue is that you are routing traffic through docker’s internal network (port mapping), which masks all incoming requests as the docker gateway ip (172.17.0.1). because internal nginx doesn’t recognize 172.17.0.1 as a cloudflare ip, it drops the CF-Connecting-IP header for security.

to fix this, you need to switch your setup to use a unix socket - this allows your outer nginx to pass the traffic (and the headers) directly into Discourse without docker’s network borking the ip addresses.

follow this official guide, and make sure you keep cloudflare.template.yml in your app.yml file when you rebuild.

That commit fixed a configuration error that you were relying on, but also that might have allowed any end user to spoof their IP address by setting that header.

If you are confident nothing else can talk to your container, there is actually an easier way that doesn’t require the use of a socket - I have just written a guide on how to do this.

For your setup @CLOUD_PHT you should add this to your container definition (if a run section already exists, add these directives to it, else add the run section):

run:
  - file:
      path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
      chmod: 644
      contents: |
        real_ip_header x-forwarded-for;
  - file:
      path: /etc/nginx/conf.d/outlets/server/set-real-ip-from-host.conf
      chmod: 644
      contents: |
        set_real_ip_from 172.17.0.1;

You may also need the following:

  - file:
      # we need to turn on recursive since we'll have at least two entries; one from the host, one from CloudFlare
      path: /etc/nginx/conf.d/outlets/server/real-ip-recursive.conf
      chmod: 644
      contents: |
        real_ip_recursive on;

depending on whether the nginx running on your server is itself processing the Cloudflare header to determine the end user’s real IP (this is suggested) or just adding its own on top. See https://meta.discourse.org/t/handling-the-chain-of-trust-of-the-end-users-real-ip/406372#p-2001772-more-than-one-proxy-7 for more details.


Other readers: be aware this this directive

run:
  - file:
      path: /etc/nginx/conf.d/outlets/server/set-real-ip-from-host.conf
      chmod: 644
      contents: |
        set_real_ip_from 172.17.0.1;

is not appropriate for all setups. Only do this if all connections to the Discourse container from this IP are trusted.

Specifically, a known problem with IPv6 setups is that IPv6 connections to the server are forwarded by docker over IPv4 - the way that it’s done make all connections look like they’re coming from the host’s docker0 IP address. If you apply the above directive to your setup, it’ll allow all users connecting over IPv6 to spoof their IP address at leisure.