Get Server IP in X_Forwarded_For instead of client IP

Hi!

1. The problem I’m having:

I have a caddy file which manage multiple projects : a few PHP projects (using file_server instruction) and nodejs project dynamically (using reverse_proxy instruction)

On my PHP project when I read the request headers, x_forwarded_for is filled with the client IP address. But on my node project, it is filled with the server IP address

2. Error messages and/or full log output:

Wrong IP

Header in node (I’ve limited to the interesting ones):

4|demo:back  | [server]       host: 'demo.codicommerce.fr',
4|demo:back  | [server]       'x-forwarded-for': '195.15.215.211',
4|demo:back  | [server]       'x-forwarded-host': 'demo.codicommerce.fr',
4|demo:back  | [server]       'x-forwarded-proto': 'https',
4|demo:back  | [server]       'x-real-ip': '195.15.215.211',
...

X-Forwarded-For is the server IP, and I tried to add X-Real-IP but with same result

Header in PHP (I’ve limited to the interesting ones and replaced part of my IP by X)

array(50) {
  ["REMOTE_ADDR"]=>
  string(12) "82.64.X.X"
  ["HTTP_X_FORWARDED_PROTO"]=>
  string(5) "https"
  ["HTTP_X_FORWARDED_HOST"]=>
  string(19) "www.codicommerce.fr"
  ["REMOTE_HOST"]=>
  string(12) "82.64.X.X"
  ["HTTP_X_FORWARDED_FOR"]=>
  string(12) "82.64.X.X"
 ...
}

It’s the client IP as it should be

3. Caddy version:

v2.7.5 h1:HoysvZkLcN2xJExEepaFHK92Qgs7xAiCFydN5x5Hs6Q=

4. How I installed and ran Caddy:

debian package

a. System environment:

Debian

b. Command:

caddy start--config /etc/caddy/Caddyfile

d. My complete Caddy config:

{
  on_demand_tls {
    ask http://localhost:8081
  }
}

http://localhost:8081 {
  root * /home/codi/clients/
  @deny not file /{query.domain}/
  respond @deny 404
}

codicommerce.fr {
  redir https://www.codicommerce.fr{uri}
}

www.codicommerce.fr {
  root * /home/codi/internal/wordpress
  php_fastcgi unix//run/php/php8.1-fpm.sock
  file_server
  encode gzip

  @disallowed {
      path /xmlrpc.php
      path *.sql
      path /wp-content/uploads/*.php
  }

  rewrite @disallowed '/index.php'
}

mon-compte.codicommerce.fr {
  root * /home/codi/internal/subscription/public
  php_fastcgi unix//run/php/php8.1-fpm.sock
  file_server
  encode gzip
}

:443 {
  tls {
    on_demand
  }
  log {
    output file /var/log/caddy/codi-access.log
  }

  root * /home/codi/clients/{host}/backend
  redir /admin /admin/ 308

  @static path /codial/files/images/* /custom/*
  handle @static {
    file_server
  }

  @admin path /admin/* /admin-api* /shop-api* /assets* /health* /codial/* /payments/stripe /newsletter-subscription/*
  handle @admin {
    reverse_proxy localhost:3001 {
      header_up X-Real-IP {remote_host}
    }
    encode gzip
  }

  handle {
    reverse_proxy localhost:3000
  }

}

Thx in advance! :slight_smile:

What is serving your node program?

Caddy already passes the X-Forwarded-For header by default.
Whatever is serving your node program will have to be configured to trust caddy as a proxy.

If you have a caddy instance downstream at localhost:3001 serving your node program, then the way to achieve this is to add a global block in the downstream Caddyfile like this

{
    servers {
        trusted_proxies static 192.168.x.x
    }
}
2 Likes

Thx for your help.

Node instances are served by pm2.
I tried adding the trusted_proxies with my server IP:

{
  servers {
    trusted_proxies static 195.15.215.211
  }

  on_demand_tls {
    ask http://localhost:8081
  }
}

http://localhost:8081 {
  root * /home/codi/clients/
  @deny not file /{query.domain}/
  respond @deny 404
}

codicommerce.fr {
  redir https://www.codicommerce.fr{uri}
}

www.codicommerce.fr {
  root * /home/codi/internal/wordpress
  php_fastcgi unix//run/php/php8.1-fpm.sock
  file_server
  encode gzip

  @disallowed {
      path /xmlrpc.php
      path *.sql
      path /wp-content/uploads/*.php
  }

  rewrite @disallowed '/index.php'
}

mon-compte.codicommerce.fr {
  root * /home/codi/internal/subscription/public
  php_fastcgi unix//run/php/php8.1-fpm.sock
  file_server
  encode gzip
}

:443 {
  tls {
    on_demand
  }
  log {
    output file /var/log/caddy/codi-access.log
  }

  root * /home/codi/clients/{host}/backend
  redir /admin /admin/ 308

  @static path /codial/files/images/* /custom/*
  handle @static {
    file_server
  }

  @admin path /admin/* /admin-api* /shop-api* /assets* /health* /codial/* /payments/stripe /newsletter-subscription/*
  handle @admin {
    reverse_proxy localhost:3001 {
      header_up X-Real-IP {remote_host}
    }
    encode gzip
  }

  handle {
    reverse_proxy localhost:3000
  }
}

But got the same result, X-Forwarded-For is my server IP, even if it’s in trusted_proxies now.

There is this documentation on pm2: PM2 - Production Setup with Nginx.
Seems with nginx they pass the header information with proxy_set_header, but not sure if I have to do something equivalent with caddy.

Thx!

You misunderstood me.

It is the pm2 server that will need to be set up to trust caddy as the proxy.

The proxy block I mentioned only applies if caddy is your downstream server, which in this case isn’t true.

Your downstream here looks like it is pm2. I don’t know how to configure pm2 or Nginx to trust a proxy. I’m sure they have docs about it

2 Likes

This doesn’t make sense – you should trust IP addresses of servers in front of Caddy. If you don’t have another proxy in front of Caddy, you should not add this.

Anyway, as @victor said, Caddy does the right thing by default. If your app isn’t receiving the correct X-Forwarded-For value, then something between Caddy and your app is the problem (i.e. pm2), and not Caddy itself. So you should get help from them.

1 Like

I understand. Pm2 is just a process manager and not what serve the app, my mistake, it just make sure node process are up and reload them if needed.

After looking a little more, it seems to be remix that “serve” node on my app.

Anyway, it’s not on caddy side apparently so I won’t bother anymore here, thanks a lot for pointing me in the right direction!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.