0

I have been struggling with the above question for countless hours and haven't been able to find an explanation for the behavior either on this site or any other site for that matter. Might be me using the wrong queries though. This is my first question on stack overflow, so please be gentle ;)

The setup I'm using:

I have a server behind my router (which has internal IP 192.168.2.254) and use port forwarding to forward public ports 80 and 443 to my (ubuntu) server. I can access that server either by typing in it's public IP (say 80.81.82.83) or by going to a domain (say example.org) which A records contain the same public IP or by typing in it's internal IP (say 192.168.2.1) when on the same network. I use NGINX on that server as a reverse proxy to delegate the request to the appropriate (web) applications on the same server. The router is the standard router I got from my internet provider.

I have two clients connecting to that server, client A is on the same network as the server (say 192.168.2.2), while client B is not on the same network, but anywhere else in the world (say 90.91.92.93).

When I connect with client B (i.e. not on the same network) to my server (either using the public IP or the domain name) and I check the NGINX access logs for the client IP (i.e. $remote_addr) the correct/expected IP address is shown: 90.91.92.93.

Now the part I don't understand:

When I connect with client A (same network as server) to the server using the internal IP of the server (192.168.2.1) the access logs show the correct/expect IP address from the client: 192.168.2.2. But when I connect from the same client to the server either using the public IP address or the domain name, the NGINX access logs shows the IP address from the router: 192.168.2.254.

Why does this happen? This way I cannot log (and act on) which internal clients connect to the server.

Maanloper
  • 73
  • 4
  • 2
    The problem is hairpin routing and NAT translation that happens with that. You should use split DNS so that the local DNS gives you the local server address. That way, the traffic stays on the LAN, never passing through the router. Hairpin routing wastes router resources and bandwidth on the router connection to and from the LAN. – Ron Maupin May 03 '21 at 21:32
  • How can one use split DNS? i.e. is it client-side or done on the router? – Maanloper May 03 '21 at 21:40
  • If you have only two clients, much simpler than setting up split DNS will be to use `hosts` file on these clients, and just put your internal IP for your domain name in this file. – raj May 03 '21 at 21:43
  • It is done on your local DNS server. Alternatively, you could change the hosts file on your workstation. – Ron Maupin May 03 '21 at 21:43

1 Answers1

2

But when I connect from the same client to the server either using the public IP address or the domain name, the NGINX access logs shows the IP address from the router: 192.168.2.254.

Why does this happen? This way I cannot log (and act on) which internal clients connect to the server.

This happens because when you connect to the public IP address (or public domain name which uses the public IP address), the connection goes from your client (192.168.2.2), to the router (192.168.2.254), then the router NATs the source address of the connection to it's own interface, i.e. to the IP address of interface closest to destination.

Jed Daniels
  • 7,282
  • 2
  • 34
  • 42
  • To extend this answer, the connection must go that way, because the public IP address is **outside** of your local network, so it must be handled by the router. It is exactly as if you were connecting to a server somewhere outside in the Internet; the server will see only your public IP address and not your client's internal IP address. – raj May 03 '21 at 21:37
  • Similar issue for me. I think there is a Watchguard Firewall or a Fortigate Router in front of an NGINX server that is running in Docker. It serves a Laravel PHP app, and I'd like to get the client IP in some cases, but the native Laravel returns the IP for the router, and a more complicated PHP script return the WAN address for the router. There are cases where I would want to get the client IP for geolocation purposes. – SScotti Nov 01 '22 at 08:08